WF提供了一組核心服務,例如在SQL 數據庫中存儲工作流實例的執行詳細信息的持久性服務,計劃服務,事務服務和跟蹤服務。除了這些WF也提供了另外一種服務,叫做Local Service也可以叫做Data exchange service。主要是實現工作流和宿主程序之間的通信,使工作流能夠使用方法和事件通過消息與外部系統交互。 事件用于將數據發送到工作流,而工作流使用方法將數據發送到主機應用程序。 通過事件與工作流進行通信的功能提供了一種將數據發送到工作流的異步方式。本文主要講述調用外部方法的部分。
下圖說明本地通信服務如何與其主機應用程序通信:
下面首先說說如何開發一個本地服務:
1.使用C#的接口定義服務契約,在接口中定義你方法和事件。并使用[ExternalDataExchangeAttribute]裝飾該接口,用于說明這是一個本地服務的接口。?
2.開發一個實現了該接口的類,用于實現你的邏輯。?
3.創建一個工作流實例,并將該本地服務添加到工作流引擎中去。
我們開發一個簡單的本地服務的例子,根據AccountID來修改Balance的值,并使用三種方式來調用:?
1.定義一個Account類,代碼如下(Account.cs)
using?System;?
namespace?CaryWorkflows?
{?
??? [Serializable]?
????public?class?Account?
??? {?
????????private?Int32 _id;?
????????private?String _name = String.Empty;?
????????private?Double _balance;?
????????public?Int32 Id?
??????? {?
????????????get?{?return?_id; }?
????????????set?{ _id =?value; }?
??????? }?
????????public?String Name?
??????? {?
????????????get?{?return?_name; }?
????????????set?{ _name =?value; }?
??????? }?
????????public?Double Balance?
??????? {?
????????????get?{?return?_balance; }?
????????????set?{ _balance =?value; }?
??????? }?
??? }?
}?
2.定義一個接口,需要ExternalDataExchange屬性,代碼如下(IAccountServices.cs):
using System; using System.Workflow.Activities; namespace CaryWorkflows {[ExternalDataExchange]public interface IAccountServices{Account AdjustBalance(Int32 id, Double adjustment);} }
3.實現該接口,代碼如下():
using System; using System.Collections.Generic; namespace CaryWorkflows {public class AccountService : IAccountServices{private Dictionary<Int32, Account> _accounts= new Dictionary<int, Account>();public AccountService(){Account account = new Account();account.Id = 101;account.Name = "Neil Armstrong";account.Balance = 100.00;_accounts.Add(account.Id, account);}public Account AdjustBalance(Int32 id, Double adjustment){Account account = null;if (_accounts.ContainsKey(id)){account = _accounts[id];account.Balance += adjustment;}return account;} } }
?
服務定義好了,我們下面就要在工作流中條用該服務,我們有三種方式:
在工作流中定義三個屬性:
using System; using System.Workflow.Activities; namespace CaryWorkflows {public sealed partial class BalanceAdjustmentWorkflow: SequentialWorkflowActivity{private Int32 _id;private Double _adjustment;private Account _account;private IAccountServices _accountServices;public Int32 Id{get { return _id; }set { _id = value; }}public Double Adjustment{get { return _adjustment; }set { _adjustment = value; }}public Account Account{get { return _account; }set { _account = value; }}public BalanceAdjustmentWorkflow(){InitializeComponent();}} }
?
然后我們向工作流中拖入一個CodeActivity,Activity有一個方法OnActivityExecutionContextLoad(),我們通過該
的IServiceProvider的GetService方法來獲取本地服務,代碼如下:
protected override void OnActivityExecutionContextLoad( IServiceProvider provider) {base.OnActivityExecutionContextLoad(provider); _accountServices = provider.GetService(typeof(IAccountServices))as IAccountServices;if (_accountServices == null){ throw new InvalidOperationException("Unable to retrieve IAccountServices from runtime");} }
?
在CodeActivity的ExecuteCode事件中調用本地服務的方法,代碼如下:
?
private void codeAdjustAccount_ExecuteCode(object sender, EventArgs e) {Account = _accountServices.AdjustBalance(Id, Adjustment); }
?
最后要將該服務添加到工作流引擎當中去,
1. 先將ExternalDataExchangeService服務對象添加到引擎。
2.再將我們自己開發的服務綁定到ExternalDataExchangeService服務中。
宿主程序的代碼如下:
using System; using System.Collections.Generic; using System.Workflow.Runtime; using System.Workflow.Activities; using CaryWorkflows ; namespace ConsoleLocalServices {public class LocalServiceTest{public static void Run(){using (WorkflowRuntimeManager manager= new WorkflowRuntimeManager(new WorkflowRuntime())){AddServices(manager.WorkflowRuntime);manager.WorkflowRuntime.StartRuntime(); Dictionary<String, Object> wfArguments= new Dictionary<string, object>(); Console.WriteLine("開始....");wfArguments.Add("Id", 101);wfArguments.Add("Adjustment", -25.00);WorkflowInstanceWrapper instance = manager.StartWorkflow(
typeof(CaryWorkflows.BalanceAdjustmentWorkflow), wfArguments);manager.WaitAll(2000);Account account = instance.OutputParameters["Account"] as Account;if (account != null){Console.WriteLine( "Revised Account: {0}, Name={1}, Bal={2:C}",account.Id,
account.Name, account.Balance);}else{Console.WriteLine("Invalid Account Id\n\r");}Console.WriteLine("結束....");}} private static void AddServices(WorkflowRuntime instance){ExternalDataExchangeService exchangeService = new ExternalDataExchangeService();instance.AddService(exchangeService); exchangeService.AddService(new AccountService());}} }
這樣我們使用代碼方式調用外部方法就結束了,結果如下:
?
?
1.添加一個app.config到項目中,代碼如下:
<?xml version="1.0" encoding="utf-8" ?> <configuration><configSections><section name="WorkflowRuntime" type="System.Workflow.Runtime.Configuration.WorkflowRuntimeSection,System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral,PublicKeyToken=31bf3856ad364e35" /><section name="LocalServices" type="System.Workflow.Activities.ExternalDataExchangeServiceSection, System.Workflow.Activities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/></configSections><WorkflowRuntime Name="ConsoleLocalServices" ><CommonParameters><!--Add parameters common to all services--></CommonParameters><Services><!--Add core services here--></Services></WorkflowRuntime><LocalServices ><Services><!--Add local services here--><add type="CaryWorkflows.AccountService, CaryWorkflows,Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /></Services></LocalServices > </configuration>2.我們只要需改動宿主程序中如下部分:?
using (WorkflowRuntimeManager manager= new WorkflowRuntimeManager(new
WorkflowRuntime("WorkflowRuntime"))); ExternalDataExchangeService exchangeService = new ExternalDataExchangeService("LocalServices");
?
1.首先自定義一個活動(AdjustAccountActivity.cs), 我們在自定義活動中獲取本地服務,并且調用其中方法,代碼如下:
using System; using System.ComponentModel; using System.Workflow.ComponentModel; using System.Workflow.Activities; namespace CaryWorkflows {public partial class AdjustAccountActivity : Activity{public static DependencyProperty IdProperty= System.Workflow.ComponentModel
.DependencyProperty.Register("Id", typeof(Int32), typeof(AdjustAccountActivity));[Description("Identifies the account")][Category("Local Services")][Browsable(true)][DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]public Int32 Id{get{return ((Int32)(base.GetValue(AdjustAccountActivity.IdProperty)));}set{base.SetValue(AdjustAccountActivity.IdProperty, value);}}public static DependencyProperty AdjustmentProperty = System.Workflow.ComponentModel.
DependencyProperty.Register("Adjustment", typeof(Double), typeof(AdjustAccountActivity));[Description("The adjustment amount")][Category("Local Services")][Browsable(true)][DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]public Double Adjustment{get{return ((Double)(base.GetValue(AdjustAccountActivity.AdjustmentProperty)));}set{base.SetValue(AdjustAccountActivity.AdjustmentProperty, value);}}public static DependencyProperty AccountProperty= System.Workflow.ComponentModel.
DependencyProperty.Register("Account", typeof(Account), typeof(AdjustAccountActivity));[Description("The revised Account object")][Category("Local Services")][Browsable(true)][DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]public Account Account{get{return ((Account)(base.GetValue( AdjustAccountActivity.AccountProperty)));}set{base.SetValue(AdjustAccountActivity.AccountProperty, value);}}public AdjustAccountActivity(){InitializeComponent();}protected override ActivityExecutionStatus Execute( ActivityExecutionContext
executionContext){IAccountServices accountServices =executionContext.GetService<IAccountServices>();if (accountServices == null){throw new InvalidOperationException( "fail IAccountServices from runtime");}Account = accountServices.AdjustBalance(Id, Adjustment);return base.Execute(executionContext);}} }
2.在工作流中我們將該自定義活動拖到工作流中,并設置相應的屬性即可。
?
?
使用該方式我們只需要拖一個CallExternalMethodActivity到工作流中,并且設置起相應屬性即可,如下圖:
這三種方式的執行結果都是一樣的。
上一篇:堅持學習WF(7):流程控制(Flow Control)
下一篇:堅持學習WF(9):本地服務之事件處理
本文轉自生魚片博客園博客,原文鏈接:http://www.cnblogs.com/carysun/archive/2008/05/09/CallExternalMethod.html,如需轉載請自行聯系原作者