我们理解了如何在启动的时候从Host传递数据给工作流,如果我们不需要从工作流返回数据的话,前面的工作就足够了。但是很多时候,我们都想要从工作流中返回一些处理的数据。 微软的工作流框架为我们提供了一个活动CallExternalMethod,来完成这样一件事。 回想上一章的列子,我们的Host程序从计算机中读取一个文件,读取一定数量的字符,在工作流中显示内容。在程序中我们要传递两个参数(一个是文件的路径,一个是从文件返回的字符数量),在工作流用MessageBox显示内容。现在,我们需要在Host的控制台中显示这些从工作流返回的信息,而不是在工作流的MessageBox中显示。如下图所示 为了实现从工作流传递数据给Host,微软提供一个专门用于这个功能的活动,叫做CallExternalMethod,这是一个好消息,坏消息是我们必须自定义一个和这个活动交流的服务模式。 交互服务模式是另外一种服务,你必须创建一个服务的接口,实现这个接口,然后在工作流运行时 Workflow runtime 中注册实现这个接口的实例。你可以实现你想要的交互,事件或者poll (这个单词不知道如何来翻译),但是你必须满足CallExternalMethod的要求。简单来说看你需要实现下面的代码结构。 创建下面的类和接口: 1、创建一个被CallExternalMethod活动调用的接口和相应的方法 2、一个实现上面的接口的类。在类中,我们要实现接口中定义的被CallExternalMethod调用的方法,方法的内容就是你的工作流发送数据到Host。 3、如果你要用事件来驱动交互,你必须实现一个继承自EventArgs 的类,用来存储你要发送给Host的信息。 在Host程序中要做下面的事情: 1、你应该创建一个ExternalDataExchangeService 类的实例,并在工作流运行时中注册它。 2、你也要在数据服务类(ExternalDataExchangeService) 中的注册你的自定义的交互服务。 3、如果你使用事件驱动交互,你还要在Host程序中进行事件的处理。 在工作流中: 1、你必须有一个叫做CallExternalMethod的活动 2、在CallExternalMethod活动中注册一个接口和调用的方法下图是类的结构你可以看见CallExternalMethod活动在另外一个线程中调用了的方法,当方法执行的时候,在Host中我们就会看到消息。 下面开始我们的代码设计,一步一步的使用CallExternalMethod来实现。1、创建下面的接口和类 你可以在单独的类库中创建接口和类,简单起见就在当前项目下面创建。namespace CommunicationCallExternalMethod{ /// <summary> /// You MUST to mark the interface with the header ExternalDataExchange /// to identify the interface as the communication interface. /// </summary> [ExternalDataExchange] public interface ICommunicationService { /// <summary> /// This method must be call by the CallExternalMethod Activity /// to transfer the information to the console host application /// </summary> /// <param name="response">Data to send to console</param> void SendDataToHost(string response); }}
从名字上面来看,很容易明白,接口的方法用来给Host发送数据。特性[ExternalDataExchange]说明类型中的方法可以被工作流调用。 2、实现上面接口的类 在类中你可以将方法实现为简单的传递数据给Host,Host poll类实例,或者你也可以用事件来异步的获取数据。 在我们的代码中我们实现了事件,我们将数据通过工作流事件的参数传递。 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CommunicationCallExternalMethod{ /// <summary> /// Implement the interface /// This implementation is made to comunicate WF -> Host /// </summary> public class CommunicationService: ICommunicationService { /// <summary> /// Event to communicate the host the result. /// </summary> public event EventHandler < SendDataToHostEventArgs > SendDataToHostEvent; /// <summary> /// Implement the external Method /// </summary> /// <param name="response"> response to host </param> public void SendDataToHost( string response) { SendDataToHostEventArgs e = new SendDataToHostEventArgs(); e.Response = response; EventHandler < SendDataToHostEventArgs > sendData = this.SendDataToHostEvent; if (sendData != null) { sendData( this, e); } } }}从上面我们可以看出来,方法只是简单的将数据传递给事件的参数,并且触发事件。事件参数的定义如下 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Workflow.Activities; namespace CommunicationCallExternalMethod{ public class SendDataToHostEventArgs: EventArgs { string _response = string.Empty; /// <summary> /// This property is used to pass in the Event the response to host /// </summary> public string Response { get { return _response; } set { _response = value; } } }} 在我们的例子中创建了三个类,分别是: SendDataToHostEventArgs.cs CommunicationService.cs ICommunicationService.cs3、注册我们自定义的交互服务作为工作流的ExternalDataExchangeService外部数据交互服务
注册过程是在工作流运行时中进行,可以参照下面的代码 ExternalDataExchangeService dataservice = new ExternalDataExchangeService(); // Add to workflow runtimeworkflowRuntime.AddService(dataservice); // Declare our CommunicationService instanceCommunicationService cservice = new CommunicationService(); // Add to the ExternalDataServicedataservice.AddService(cservice); // Add a handler to Service Eventcservice.SendDataToHostEvent += new EventHandler < senddatatohosteventargs > (cservice_SendDataToHostEvent);第一步是注册交互服务,接下来是注册事件的处理程序4、在工作流设计界面进行设置就用上一章我们建立的工作流就可以,拖拽一个CallExternalMethod 活动到设计界面上来,设置如下选择InterfaceType 属性为ICommunicationService,在MethodName属性中选择接口的SendDataToHost方法,将方法的参数response,也就是消息的内容绑定到工作流的一个属性上来,可以实现动态绑定更新工作流的属性。使用CallExternalMethod 活动, 从工作流传递数据给Host的基本步骤如下:1、创建下面的接口和类 1)一个被CallExternalMethod 活动调用的接口方法,并且标记接口为[ExternalDataExchange] 2)一个实现接口的类,类中实现被[CallExternalMethod ]活动调用的方法,2、在Host程序中做下面的事情 1)为工作流运行时注册一个ExternalDataExchangeService类 的实例 ExternalDataExchangeService dataservice = new ExternalDataExchangeService(); //Add to workflow runtime workflowRuntime.AddService(dataservice); 2)为ExternalDataExchangeService类 的实例添加交互的实例 CommunicationService cservice = new CommunicationService(); //Add to the ExternalDataService dataservice.AddService(cservice); //Add a handler to Service Event 3)如果你使用事件驱动交互,在你的Host程序中要定义事件处理 cservice.SendDataToHostEvent += new EventHandler<SendDataToHostEventArgs>(cservice_SendDataToHostEvent); 3、在工作流中 1)拖拽一个CallExternalMethod 活动到设计器中, 2)设置CallExternalMethod 活动的接口和方法,绑定参数 现在为止,你有了一个从Host到工作流的单向交互,但是你还是有局限,直到现在你只是知道如何给工作流传递初始化数据,但是你还不知道在如何随时给工作流传递参数?在下一章我们将会讲到这些。【Blog】http://virusswb.cnblogs.com/