六、定義在工作流實例與宿主間通信的本地服務
WWF中的服務可分為核心服務和本地服務。核心服務由WF定義,而本地服務(也稱為數據交換服務) 則是開發人員自定義的。本地服務可以是任何想在WF中實現的服務,一個通常的用處是使用本地服務在工作流實例與宿主之間進行通信。有關於“本地服務”的全面討論是一個復雜的話題,我想在本系列後面的學習教程中對之展開全面深入的探討,在此不贅述。
[一]定義接口
根據WWF中本地服務的定義要求,首先要定義一個修飾以ExternalDataExchange屬性的接口,我們對之命名為ILocalService,代碼如下:
[ExternalDataExchange]
internal interface ILocalService
{
event EventHandler<ExternalDataEventArgs> InvokedWorkflowComplete;
void WorkComplete(Guid HostWFGuid);
}
[二]創建本地服務類
然後,基於上述接口創建一個本地服務類,代碼如下:
//定義一個本地服務實現,該服務將被添加到工作流運行時引擎中
internal class LocalService : ILocalService
{
public event EventHandler<ExternalDataEventArgs> InvokedWorkflowComplete;
public void WorkComplete(Guid HostWFGuid)//實現接口中聲明的方法
{
if (InvokedWorkflowComplete != null)
{
InvokedWorkflowComplete(null, new ExternalDataEventArgs(HostWFGuid));
}
}
}
上面定義中,基本遵循了“死”格式,除了方法名稱外。在本文中先不詳細討論。
七、在宿主中操作工作流實例與本地服務
根據前面的要求,本地服務負責工作流實例與宿主間的通信中介,而加載本地服務的工作是在宿主中完成的。下面給出了宿主部分(program.cs)完整的代碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
using System.Workflow.ActivitIEs;//ExternalDataExehangeService
namespace InvokeWorkflowActivityDemo
{
class Program
{
static Guid HostWFGuid;//用於記憶父工作流實例的ID標記
static LocalService ls;
static void Main(string[] args)
{
using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
//下面這幾行是必需的死套路
//加載本地服務
ExternalDataExchangeService dataService = new ExternalDataExchangeService();
workflowRuntime.AddService(dataService);
//將自定義的本地通信服務加載到本地服務中
ls = new LocalService();
dataService.AddService(ls);
//事件初始狀態為終止狀態(此時任何線程可以使用此事件)
AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e)
{
//如果將要產生僅一個子工作流,那麼需要檢查工作流是否完成,而不是主工作流。
if (e.WorkflowInstance.InstanceId != HostWFGuid)
{
//通過本地服務的特定方法通知主工作流,調用工作流完成
ls.WorkComplete(HostWFGuid);
}
else
{
//此時是主工作流自身,將事件的狀態位置設置為終止狀態,允許一個或多個等待線程繼續。
waitHandle.Set();
}
};
workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Message);
waitHandle.Set();
};
//啟動父工作流實例
WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(Workflow1));
HostWFGuid = instance.InstanceId;//記下父工作流實例的ID標記
instance.Start();
waitHandle.WaitOne();//阻止當前線程,直到當前waitHandle收到信號。
Console.ReadLine();
}
}
}
}
根據MSDN聲明,啟動工作流的實例之前,必須將 ExternalDataExchangeService 添加到工作流運行時引擎,然後將自定義通信服務添加到 ExternalDataExchangeService。詳情請參考MSDN文章《在工作流中使用本地服務》。
八、運行實例
按F5運行控制台程序,一般順利的話,將得到如下圖所示運行時快照。