大家知道,Workflow可以通过两种方法来调用外部的代码,也就是常说的local service,这两种方法分别为CallExternalMethodActivity 与 HandleExternalEventActivity。
1.CallExternalMethodActivity
当Workflow 需要主动的去调用外部的代码中的一个方法时使用CallExternalMethodActivity
2. HandleExternalEventActivity
当Workflow 等待外部代码中的一个事件发生,并作出响应,这时候可以使用HandleExternalEventActivity
好了,废话不多说,下面通过一个例子来介绍如何使用这两种Activity:
1.首先在VS 2008 中创建一个Sequential Workflow Library项目,将workflow1.cs改名为WfCallTwoKindsExternalMethod.cs,向其中拖入CallExternalMethodActivity 和HandleExternalEventActivity两个Activity:
2.要让Workflow可以调用,必须先声明一个外部方法的接口,并且标明[ExternalDataExchange]属性。
我们创建IExternalMethodCalling,代码如下:
[ExternalDataExchange]
public interface IExternalMethodCalling
{
void SendMessage(string message);
event EventHandler<ExternalArgs.ExternalArgs> WorkflowMessageChanged;
}
注意,接口是外部方法的唯一标识,故不能有2个实现同样接口的外部方法,因为Workflow通过接口来决定调用那个外部方法,如有2个实现同样接口的外部方法Workflow无法区分要调用的是哪个外部方法。
3.现在我们来实现本地外部代码,也就是Workflow要调用的代码:
[Serializable]
public class LocalService:IExternalMethodCalling
{
public event EventHandler<ExternalArgs.ExternalArgs> UIMessageUpdated;
public string Message { get; set; }
/// <summary>
/// The local service method called by CallExternalMethodActivity, transfer the workflow id and the message from workflow property
/// </summary>
/// <param name="message"></param>
public void SendMessage(string message)
{
if (null != UIMessageUpdated)
{
this.Message = message;
ExternalArgs.ExternalArgs args = new WfEventCalling.ExternalArgs.ExternalArgs(WorkflowEnvironment.WorkflowInstanceId, message);
UIMessageUpdated(this, args);
}
}
public event EventHandler<ExternalArgs.ExternalArgs> WorkflowMessageChanged;
public void OnWorkflowMessageChanged(ExternalArgs.ExternalArgs args)
{
WorkflowMessageChanged(null, args);
}
}
在这个例子中,CallExternalMethodActivity 要调用外部方法中的SendMessage方法,而当外部方法中的OnWorkflowMessageChanged运行时,会触发HandleExternalEventActivity。
这里的ExternalArgs是我们自己实现的,因为Workflow实例都是单独运行在不同的线程上,要HandleExternalEventActivity等待外部事件的触发,必须告诉HandleExternalEventActivity正确的Workflow 实例ID,这样当外部方法中的一个事件促发时,才能使得相应的Workflow实例来响应。因为事件是通过EventArgs来传递参数,这样,我们可以实现一个包含Workflow instance id信息的参数类
[Serializable]
public class ExternalArgs:ExternalDataEventArgs
{
public string Message { get; set; }
public ExternalArgs(Guid instanceId, string message)
: base(instanceId)
{
this.Message = message;
}
}
4.配置 Workflow 中的两个Activity
CallExternalMethodActivity:
CallExternalMethodActivity1的属性栏中,在InterfaceType中输入我们定义的接口IExternalMethodCalling。
在MethodName中选择要调用的外部方法:SendMessage,注意这个外部方法需要提供一个string类型的参数,因此我们在workflow的代码中创建一个Message属性,然后在message一栏中,将其绑定为Message属性。
HandleExternalEventActivity:
handleExternalEventActivity1 属性中作类似配置,选择外部接口,等待触发的事件,唯一不同的是要提供外部事件触发后的响应事件代码,在Workflow代码中创建
private void handleExternalEventActivity1_Invoked(object sender, ExternalDataEventArgs e)
{
ExternalArgs.ExternalArgs args = e as ExternalArgs.ExternalArgs;
this.Message = this.Message + " has been handled by workflow";
Console.WriteLine(this.Message);
}
在handleExternalEventActivity1 属性中的Invoked一栏作绑定。
工作流的设置就这样完成。
因为我们创建的是一个Workflow lirbary,所以无法直接运行,下面我们来创建运行workflow的代码
添加一个控制台应用程序的项目,program.cs中如下:
class Program:IDisposable
{
private WorkflowRuntime _workflowRuntime;
private Guid wfInstanceId = Guid.Empty;
private WfEventCalling.LocalService.LocalService localService = null;
AutoResetEvent _waitHandle = new AutoResetEvent(false);
public Program()
{
InitializeWorkflowRuntime();
}
static void Main(string[] args)
{
using (Program instance = new Program())
{
string msg = String.Empty;
instance.AddService(instance._workflowRuntime);
while (true)
{
msg = Console.ReadLine();
if (msg != "exit")
{
Dictionary<string, object> wfArgs = new Dictionary<string, object>();
wfArgs.Add("Message", msg);
instance.RunWorkflow(wfArgs, typeof(WfEventCalling.WfCallTwoKindsExternalMethod));
}
else
{
break;
}
}
}
}
public void Dispose()
{
_workflowRuntime.StopRuntime();
_workflowRuntime.Dispose();
}
private void AddService(WorkflowRuntime instance)
{
System.Workflow.Activities.ExternalDataExchangeService service = new System.Workflow.Activities.ExternalDataExchangeService();
instance.AddService(service);
localService = new WfEventCalling.LocalService.LocalService();
localService.UIMessageUpdated +=new EventHandler<WfEventCalling.ExternalArgs.ExternalArgs>(localService_UIMessageUpdated);
service.AddService(localService);
}
private void localService_UIMessageUpdated(object sender, WfEventCalling.ExternalArgs.ExternalArgs e)
{
this.wfInstanceId = e.InstanceId;
if (null != localService)
{
WfEventCalling.ExternalArgs.ExternalArgs args = new WfEventCalling.ExternalArgs.ExternalArgs(wfInstanceId, "");
localService.OnWorkflowMessageChanged(args);
}
}
private void InitializeWorkflowRuntime()
{
_workflowRuntime = new WorkflowRuntime();
_workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e)
{
_waitHandle.Set();
};
_workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
{
Console.Write(e.Exception.Message);
_waitHandle.Set();
};
_workflowRuntime.StartRuntime();
}
public void RunWorkflow(Dictionary<string, object> wfArgument, Type workflowType)
{
WorkflowInstance instance = _workflowRuntime.CreateWorkflow(workflowType, wfArgument);
instance.Start();
//wait the workflow to complete
_waitHandle.WaitOne();
}
}
AddService方法向workflow注册了要调用的外部方法类,并为外部方法中的事件提供了响应方法,向Workflow的属性传了值。
运行此控制台程序,调用顺序如下:
运行Main方法,向工作流属性Message传了值,Workflow中CallExternalMethodActivity1运行,调用外部方法SendMessage,促发了UIMessageUpdated事件,UIMessageUpdated调用了外部方法中的OnWorkflowMessageChanged方法,促发了handleExternalEventActivity1的等待事件WorkflowMessageChanged,handleExternalEventActivity1响应方法运行。其中message参数的值就顺着workflow得到了处理。
除非你在控制台窗口中输入“exit",否则workflow将一直处理输入的message字符串。
所有详细代码都在: