您的位置:首页 > 其它

坚持学习WF(8):本地服务之调用外部方法

2008-05-09 08:17 633 查看
WF提供了一组核心服务,例如在SQL数据库中存储工作流实例的执行详细信息的持久性服务,计划服务,事务服务和跟踪服务。除了这些WF也提供了另外一种服务,叫做LocalService也可以叫做Dataexchangeservice。主要是实现工作流和宿主程序之间的通信,使工作流能够使用方法和事件通过消息与外部系统交互。事件用于将数据发送到工作流,而工作流使用方法将数据发送到主机应用程序。通过事件与工作流进行通信的功能提供了一种将数据发送到工作流的异步方式。本文主要讲述调用外部方法的部分。

下图说明本地通信服务如何与其主机应用程序通信:





下面首先说说如何开发一个本地服务:

1.使用C#的接口定义服务契约,在接口中定义你方法和事件。并使用[ExternalDataExchangeAttribute]装饰该接口,用于说明这是一个本地服务的接口。
2.开发一个实现了该接口的类,用于实现你的逻辑。
3.创建一个工作流实例,并将该本地服务添加到工作流引擎中去。

我们开发一个简单的本地服务的例子,根据AccountID来修改Balance的值,并使用三种方式来调用:
1.定义一个Account类,代码如下(Account.cs)

usingSystem;
namespaceCaryWorkflows
{
[Serializable]
publicclassAccount
{
privateInt32_id;
privateString_name=String.Empty;
privateDouble_balance;

publicInt32Id
{
get{return_id;}
set{_id=value;}
}
publicStringName
{
get{return_name;}
set{_name=value;}
}
publicDoubleBalance
{
get{return_balance;}
set{_balance=value;}
}
}
}
2.定义一个接口,需要ExternalDataExchange属性,代码如下(IAccountServices.cs):

usingSystem;
usingSystem.Workflow.Activities;
namespaceCaryWorkflows
{
[ExternalDataExchange]
publicinterfaceIAccountServices
{
AccountAdjustBalance(Int32id,Doubleadjustment);
}
}

3.实现该接口,代码如下():

usingSystem;
usingSystem.Collections.Generic;
namespaceCaryWorkflows
{
publicclassAccountService:IAccountServices
{
privateDictionary<Int32,Account>_accounts=newDictionary<int,Account>();
publicAccountService()
{
Accountaccount=newAccount();
account.Id=101;
account.Name="NeilArmstrong";
account.Balance=100.00;
_accounts.Add(account.Id,account);
}
publicAccountAdjustBalance(Int32id,Doubleadjustment)
{
Accountaccount=null;
if(_accounts.ContainsKey(id))
{
account=_accounts[id];
account.Balance+=adjustment;
}
returnaccount;
}
}
}
服务定义好了,我们下面就要在工作流中条用该服务,我们有三种方式:
代码方式
在工作流中定义三个属性:
usingSystem;
usingSystem.Workflow.Activities;
namespaceCaryWorkflows
{
publicsealedpartialclassBalanceAdjustmentWorkflow:SequentialWorkflowActivity
{
privateInt32_id;
privateDouble_adjustment;
privateAccount_account;
privateIAccountServices_accountServices;

publicInt32Id
{
get{return_id;}
set{_id=value;}
}
publicDoubleAdjustment
{
get{return_adjustment;}
set{_adjustment=value;}
}
publicAccountAccount
{
get{return_account;}
set{_account=value;}
}
publicBalanceAdjustmentWorkflow()
{
InitializeComponent();
}
}
}
然后我们向工作流中拖入一个CodeActivity,Activity有一个方法OnActivityExecutionContextLoad(),我们通过该
的IServiceProvider的GetService方法来获取本地服务,代码如下:
protectedoverridevoidOnActivityExecutionContextLoad(IServiceProviderprovider)
{
base.OnActivityExecutionContextLoad(provider);
_accountServices=provider.GetService(typeof(IAccountServices))asIAccountServices;
if(_accountServices==null)
{
thrownewInvalidOperationException("UnabletoretrieveIAccountServicesfromruntime");
}
}
在CodeActivity的ExecuteCode事件中调用本地服务的方法,代码如下:
privatevoidcodeAdjustAccount_ExecuteCode(objectsender,EventArgse)
{
Account=_accountServices.AdjustBalance(Id,Adjustment);
}
最后要将该服务添加到工作流引擎当中去,
1.先将ExternalDataExchangeService服务对象添加到引擎。
2.再将我们自己开发的服务绑定到ExternalDataExchangeService服务中。
宿主程序的代码如下:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Workflow.Runtime;
usingSystem.Workflow.Activities;
usingCaryWorkflows;
namespaceConsoleLocalServices
{
publicclassLocalServiceTest
{
publicstaticvoidRun()
{
using(WorkflowRuntimeManagermanager=newWorkflowRuntimeManager(newWorkflowRuntime()))
{
AddServices(manager.WorkflowRuntime);
manager.WorkflowRuntime.StartRuntime();
Dictionary<String,Object>wfArguments=newDictionary<string,object>();
Console.WriteLine("开始....");
wfArguments.Add("Id",101);
wfArguments.Add("Adjustment",-25.00);
WorkflowInstanceWrapperinstance=manager.StartWorkflow(
typeof(CaryWorkflows.BalanceAdjustmentWorkflow),wfArguments);
manager.WaitAll(2000);
Accountaccount=instance.OutputParameters["Account"]asAccount;
if(account!=null)
{
Console.WriteLine("RevisedAccount:{0},Name={1},Bal={2:C}",account.Id,
account.Name,account.Balance);
}
else
{
Console.WriteLine("InvalidAccountId\n\r");
}

Console.WriteLine("结束....");
}
}
privatestaticvoidAddServices(WorkflowRuntimeinstance)
{
ExternalDataExchangeServiceexchangeService=newExternalDataExchangeService();
instance.AddService(exchangeService);
exchangeService.AddService(newAccountService());
}
}
}
这样我们使用代码方式调用外部方法就结束了,结果如下:
开始....
RevisedAccount:101,Name=NeilArmstrong,Bal=¥75.00
结束....
配置文件方式
1.添加一个app.config到项目中,代码如下:
<?xmlversion="1.0"encoding="utf-8"?>
<configuration>
<configSections>
<sectionname="WorkflowRuntime"
type="System.Workflow.Runtime.Configuration.WorkflowRuntimeSection,
System.Workflow.Runtime,Version=3.0.00000.0,Culture=neutral,
PublicKeyToken=31bf3856ad364e35"/>
<sectionname="LocalServices"
type="System.Workflow.Activities.ExternalDataExchangeServiceSection,
System.Workflow.Activities,Version=3.0.0.0,Culture=neutral,
PublicKeyToken=31bf3856ad364e35"/>
</configSections>
<WorkflowRuntimeName="ConsoleLocalServices">
<CommonParameters>
<!--Addparameterscommontoallservices-->
</CommonParameters>
<Services>
<!--Addcoreserviceshere-->
</Services>
</WorkflowRuntime>
<LocalServices>
<Services>
<!--Addlocalserviceshere-->
<addtype="CaryWorkflows.AccountService,
CaryWorkflows,Version=1.0.0.0,
Culture=neutral,PublicKeyToken=null"/>
</Services>
</LocalServices>
</configuration>
2.我们只要需改动宿主程序中如下部分:
using(WorkflowRuntimeManagermanager=newWorkflowRuntimeManager(new
WorkflowRuntime("WorkflowRuntime")));
ExternalDataExchangeServiceexchangeService=newExternalDataExchangeService("LocalServices");
使用自定义活动方式

1.首先自定义一个活动(AdjustAccountActivity.cs),我们在自定义活动中获取本地服务,并且调用其中方法,代码如下:
usingSystem;
usingSystem.ComponentModel;
usingSystem.Workflow.ComponentModel;
usingSystem.Workflow.Activities;
namespaceCaryWorkflows
{
publicpartialclassAdjustAccountActivity:Activity
{
publicstaticDependencyPropertyIdProperty=System.Workflow.ComponentModel
.DependencyProperty.Register("Id",typeof(Int32),typeof(AdjustAccountActivity));
[Description("Identifiestheaccount")]
[Category("LocalServices")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
publicInt32Id
{
get
{
return((Int32)(base.GetValue(AdjustAccountActivity.IdProperty)));
}
set
{
base.SetValue(AdjustAccountActivity.IdProperty,value);
}
}

publicstaticDependencyPropertyAdjustmentProperty=System.Workflow.ComponentModel.
DependencyProperty.Register("Adjustment",typeof(Double),typeof(AdjustAccountActivity));
[Description("Theadjustmentamount")]
[Category("LocalServices")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
publicDoubleAdjustment
{
get
{
return((Double)(base.GetValue(AdjustAccountActivity.AdjustmentProperty)));
}
set
{
base.SetValue(AdjustAccountActivity.AdjustmentProperty,value);
}
}

publicstaticDependencyPropertyAccountProperty=System.Workflow.ComponentModel.
DependencyProperty.Register("Account",typeof(Account),typeof(AdjustAccountActivity));
[Description("TherevisedAccountobject")]
[Category("LocalServices")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
publicAccountAccount
{
get
{
return((Account)(base.GetValue(AdjustAccountActivity.AccountProperty)));
}
set
{
base.SetValue(AdjustAccountActivity.AccountProperty,value);
}
}

publicAdjustAccountActivity()
{
InitializeComponent();
}

protectedoverrideActivityExecutionStatusExecute(ActivityExecutionContext
executionContext)
{
IAccountServicesaccountServices=executionContext.GetService<IAccountServices>();
if(accountServices==null)
{
thrownewInvalidOperationException("failIAccountServicesfromruntime");
}
Account=accountServices.AdjustBalance(Id,Adjustment);
returnbase.Execute(executionContext);
}
}
}
2.在工作流中我们将该自定义活动拖到工作流中,并设置相应的属性即可。
使用CallExternalMethodActivity
使用该方式我们只需要拖一个CallExternalMethodActivity到工作流中,并且设置起相应属性即可,如下图:


这三种方式的执行结果都是一样的。
上一篇:坚持学习WF(7):流程控制(FlowControl)
下一篇:坚持学习WF(9):本地服务之事件处理
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: