汤尼

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

大家知道,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字符串。

 

所有详细代码都在:

/Files/tonnie/WorkflowSet.rar

posted on 2009-11-17 15:32  Tonnie  阅读(1548)  评论(1编辑  收藏  举报