[置顶]坚持学习WF文章索引

一:当我们在工作流中使用本地服务的事件的时候,WF运行时引擎将入站消息映射到实例中的特定的HandleExternalEventActivity活动,对实例的映射是在将工作流实例InstanceId传递到ExternalDataEventArgs构造函数时完成的。所以当工作流实例在本地服务接口上侦听相同事件的不同实例时,就无法确定该响应哪个事件。如下图:

坚持学习WF(10):在工作流中使用关联

如何解决这个问题呢,我们就需要在工作流中使用关联,通过使用接口属性来定义关联,使用关联后通信活动会多出一个CorrelationToken属性(关联标记)。当宿主中要触发一个外部事件时,可以传递两个参数,一个是实例的ID号,一个是关联标记编号。这样就可以将事件路由到该工作流实例中正确的活动。

使用关联时要成对使用CallExternalMethodActivity与HandleExternalEventActivity。

下面看下关联的接口属性:

CorrelationParameterAttribute 
用于指定在接口中定义的方法和事件的用于关联的参数名称。 如果方法或事件包含一个与该名称匹配的形参,则该参数定义该方法或事件上的相关值。 如果方法或事件没有此类参数,则方法或事件可以使用 CorrelationAliasAttribute 来定义相关值的位置。 此属性在一个接口中可以出现多次。

CorrelationInitializerAttribute 
用于在方法或事件中指示相关参数的值是在调用该方法或引发该事件时初始化的。 对于给定的 CorrelationToken,必须在对话中的任何其他方法或事件执行之前调用或接收初始值设定项方法或事件。 任何可以初始化新对话(即新的相关令牌)的方法或事件都必须使用此属性进行标记。 对于每个相关令牌,方法或事件必须包含一个适当的命名参数或一个 CorrelationAliasAttribute。

CorrelationAliasAttribute 
在方法或事件定义中用来重写该成员的 CorrelationParameter 设置。 CorrelationAliasAttribute 属性指定可用参数中可以获得相关值的位置。 该字符串参数是针对形参集的以点分隔的路径。 该参数指示在何处可以找到匹配数据值。 如果定义了多个相关令牌,还必须指定令牌 Name 命名参数。

二:下面是个小例子,该示例中工作流将创建两个任务,然后在这些任务完成时等待(同一本地服务事件)通知。 在这种情况下,当外部代码将事件引发到工作流时,本地服务基础结构必须依赖于所引发事件中的数据(相关值)将事件路由到工作流实例中相应的 HandleExternalEventActivity 活动。

每创建一项任务,任务服务就会显示一个消息框,通知用户任务已创建。 单击了“确定”按钮后,将为对应的任务 ID 引发用以完成任务的事件。 这些属性与 CreateTask 活动上设置的属性相同,因此事件与正确的 TaskCompleted 活动关联。

1.事件参数类TaskEventArgs:

坚持学习WF(10):在工作流中使用关联[Serializable]
坚持学习WF(10):在工作流中使用关联    public class TaskEventArgs : ExternalDataEventArgs
坚持学习WF(10):在工作流中使用关联    {
坚持学习WF(10):在工作流中使用关联        string idValue;
坚持学习WF(10):在工作流中使用关联        string assigneeValue;
坚持学习WF(10):在工作流中使用关联        string textValue;
坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        public TaskEventArgs(Guid instanceId, string id, string assignee, string text)
坚持学习WF(10):在工作流中使用关联            :base(instanceId)
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            this.idValue = id;
坚持学习WF(10):在工作流中使用关联            this.assigneeValue = assignee;
坚持学习WF(10):在工作流中使用关联            this.textValue = text;
坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        public string Id
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            get return this.idValue; }
坚持学习WF(10):在工作流中使用关联            set this.idValue = value; }
坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        public string Assignee
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            get return this.assigneeValue; }
坚持学习WF(10):在工作流中使用关联            set this.assigneeValue = value; }
坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        public string Text
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            get return this.textValue; }
坚持学习WF(10):在工作流中使用关联            set this.textValue = value; }
坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联    }

坚持学习WF(10):在工作流中使用关联

2.定义服务接口:   

坚持学习WF(10):在工作流中使用关联[ExternalDataExchange]
坚持学习WF(10):在工作流中使用关联    [CorrelationParameter("taskId")]
坚持学习WF(10):在工作流中使用关联    public interface ITaskService
坚持学习WF(10):在工作流中使用关联    {         
坚持学习WF(10):在工作流中使用关联        [CorrelationInitializer]
坚持学习WF(10):在工作流中使用关联        void CreateTask(string taskId, string assignee, string text);
坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        [CorrelationAlias("taskId""e.Id")]
坚持学习WF(10):在工作流中使用关联
        event EventHandler<TaskEventArgs> TaskCompleted;
坚持学习WF(10):在工作流中使用关联    }


注意:2.1 [CorrelationParameter("taskId")] 中的"taskId"和CreateTask方法中的string taskId要一致。
           2.2 [CorrelationAlias("taskId", "e.Id")] 关联参数的别名绑定。 

 

3.实现服务类:
坚持学习WF(10):在工作流中使用关联public class TaskService : ITaskService
坚持学习WF(10):在工作流中使用关联    {
坚持学习WF(10):在工作流中使用关联        public void CreateTask(string taskId, string assignee, string text)
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            Console.WriteLine("task " + taskId + " created for " + assignee);
坚持学习WF(10):在工作流中使用关联            ThreadPool.QueueUserWorkItem(ShowDialog, new TaskEventArgs(WorkflowEnvironment.WorkflowInstanceId, taskId, assignee, text));
坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        public void RaiseEvent(TaskEventArgs args)
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            EventHandler<TaskEventArgs> taskCompleted = this.TaskCompleted;
坚持学习WF(10):在工作流中使用关联            if (taskCompleted != null)
坚持学习WF(10):在工作流中使用关联                taskCompleted(null, args);
坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        public void ShowDialog(object state)
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            TaskEventArgs taskEventArgs = state as TaskEventArgs;
坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联            MessageBox.Show(string.Format("{0}, click OK when '{1}' completed.", taskEventArgs.Assignee, taskEventArgs.Text), string.Format("Task {0}", taskEventArgs.Id), MessageBoxButtons.OK);
坚持学习WF(10):在工作流中使用关联            
坚持学习WF(10):在工作流中使用关联            RaiseEvent(taskEventArgs);
坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        public event EventHandler<TaskEventArgs> TaskCompleted;
坚持学习WF(10):在工作流中使用关联    }

坚持学习WF(10):在工作流中使用关联

4.创建自定义通信活动

4.1 CreateTask活动继承自CallExternalMethodActivity,来调用本地服务中的方法,在构造函数中设定InterfaceType和MethodName属性。代码如下:


坚持学习WF(10):在工作流中使用关联[ToolboxItemAttribute(typeof(ActivityToolboxItem))]
坚持学习WF(10):在工作流中使用关联    public partial class CreateTask : System.Workflow.Activities.CallExternalMethodActivity
坚持学习WF(10):在工作流中使用关联    {
坚持学习WF(10):在工作流中使用关联        // Properties on the task
坚持学习WF(10):在工作流中使用关联
        public static DependencyProperty AssigneeProperty = DependencyProperty.Register("Assignee"typeof(System.String), typeof(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask));
坚持学习WF(10):在工作流中使用关联        public static DependencyProperty TaskIdProperty = DependencyProperty.Register("TaskId"typeof(System.String), typeof(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask));
坚持学习WF(10):在工作流中使用关联        public static DependencyProperty TextProperty = DependencyProperty.Register("Text"typeof(System.String), typeof(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask));
坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        private void InitializeComponent()
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联    
坚持学习WF(10):在工作流中使用关联        public CreateTask()
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            this.InterfaceType = typeof(Microsoft.Samples.Workflow.CorrelatedLocalService.ITaskService);
坚持学习WF(10):在工作流中使用关联            this.MethodName = "CreateTask";
坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
坚持学习WF(10):在工作流中使用关联        [BrowsableAttribute(true)]
坚持学习WF(10):在工作流中使用关联        public string Assignee
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            get
坚持学习WF(10):在工作流中使用关联            {
坚持学习WF(10):在工作流中使用关联                return ((string)(base.GetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.AssigneeProperty)));
坚持学习WF(10):在工作流中使用关联            }

坚持学习WF(10):在工作流中使用关联            set
坚持学习WF(10):在工作流中使用关联            {
坚持学习WF(10):在工作流中使用关联                base.SetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.AssigneeProperty, value);
坚持学习WF(10):在工作流中使用关联            }

坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
坚持学习WF(10):在工作流中使用关联        [BrowsableAttribute(true)]
坚持学习WF(10):在工作流中使用关联        public string TaskId
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            get
坚持学习WF(10):在工作流中使用关联            {
坚持学习WF(10):在工作流中使用关联                return ((string)(base.GetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.TaskIdProperty)));
坚持学习WF(10):在工作流中使用关联            }

坚持学习WF(10):在工作流中使用关联            set
坚持学习WF(10):在工作流中使用关联            {
坚持学习WF(10):在工作流中使用关联                base.SetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.TaskIdProperty, value);
坚持学习WF(10):在工作流中使用关联            }

坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
坚持学习WF(10):在工作流中使用关联        [BrowsableAttribute(true)]
坚持学习WF(10):在工作流中使用关联        public string Text
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            get
坚持学习WF(10):在工作流中使用关联            {
坚持学习WF(10):在工作流中使用关联                return ((string)(base.GetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.TextProperty)));
坚持学习WF(10):在工作流中使用关联            }

坚持学习WF(10):在工作流中使用关联            set
坚持学习WF(10):在工作流中使用关联            {
坚持学习WF(10):在工作流中使用关联                base.SetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.TextProperty, value);
坚持学习WF(10):在工作流中使用关联            }

坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        protected override void OnMethodInvoking(EventArgs e)
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            this.ParameterBindings["taskId"].Value = this.TaskId;
坚持学习WF(10):在工作流中使用关联            this.ParameterBindings["assignee"].Value = this.Assignee;
坚持学习WF(10):在工作流中使用关联            this.ParameterBindings["text"].Value = this.Text;
坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联       
坚持学习WF(10):在工作流中使用关联    }

坚持学习WF(10):在工作流中使用关联


4.2 TaskCompleted活动继承自HandleExternalEventActivity,来处理本地服务中的事件,在构造函数中设定
InterfaceType和EventName属性。代码如下:
坚持学习WF(10):在工作流中使用关联[ToolboxItemAttribute(typeof(ActivityToolboxItem))]
坚持学习WF(10):在工作流中使用关联    public partial class TaskCompleted : System.Workflow.Activities.HandleExternalEventActivity
坚持学习WF(10):在工作流中使用关联    {
坚持学习WF(10):在工作流中使用关联        // properties
坚持学习WF(10):在工作流中使用关联
        public static DependencyProperty SenderProperty = System.Workflow.ComponentModel.DependencyProperty.Register("Sender"typeof(Object), typeof(TaskCompleted));
坚持学习WF(10):在工作流中使用关联        public static DependencyProperty EProperty = System.Workflow.ComponentModel.DependencyProperty.Register("E"typeof(TaskEventArgs), typeof(TaskCompleted));
坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        public TaskCompleted()
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            this.EventName = "TaskCompleted";
坚持学习WF(10):在工作流中使用关联            this.InterfaceType = typeof(Microsoft.Samples.Workflow.CorrelatedLocalService.ITaskService);
坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联        
坚持学习WF(10):在工作流中使用关联        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
坚持学习WF(10):在工作流中使用关联        [BrowsableAttribute(true)]
坚持学习WF(10):在工作流中使用关联        public object Sender
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            get
坚持学习WF(10):在工作流中使用关联            {
坚持学习WF(10):在工作流中使用关联                return ((Object)(base.GetValue(TaskCompleted.SenderProperty)));
坚持学习WF(10):在工作流中使用关联            }

坚持学习WF(10):在工作流中使用关联            set
坚持学习WF(10):在工作流中使用关联            {
坚持学习WF(10):在工作流中使用关联                base.SetValue(TaskCompleted.SenderProperty, value);
坚持学习WF(10):在工作流中使用关联            }

坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        public static DependencyProperty EventArgsProperty = System.Workflow.ComponentModel.DependencyProperty.Register("EventArgs"typeof(TaskEventArgs), typeof(TaskCompleted));
坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
坚持学习WF(10):在工作流中使用关联        [BrowsableAttribute(true)]
坚持学习WF(10):在工作流中使用关联        public Microsoft.Samples.Workflow.CorrelatedLocalService.TaskEventArgs EventArgs
坚持学习WF(10):在工作流中使用关联              {
坚持学习WF(10):在工作流中使用关联            get
坚持学习WF(10):在工作流中使用关联            {
坚持学习WF(10):在工作流中使用关联                return ((TaskEventArgs)(base.GetValue(TaskCompleted.EventArgsProperty)));
坚持学习WF(10):在工作流中使用关联            }

坚持学习WF(10):在工作流中使用关联            set
坚持学习WF(10):在工作流中使用关联            {
坚持学习WF(10):在工作流中使用关联                base.SetValue(TaskCompleted.EventArgsProperty, value);
坚持学习WF(10):在工作流中使用关联            }

坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        protected override void OnInvoked(EventArgs e)
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            EventArgs = e as TaskEventArgs;
坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联    }


5.实现工作流如下图:
 
完整代码如下:

坚持学习WF(10):在工作流中使用关联 public sealed partial class CorrelatedLocalServiceWorkflow : SequentialWorkflowActivity
坚持学习WF(10):在工作流中使用关联    {
坚持学习WF(10):在工作流中使用关联        public CorrelatedLocalServiceWorkflow()
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            InitializeComponent();
坚持学习WF(10):在工作流中使用关联        }
        
坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        private void OnTaskCompleted(object sender, ExternalDataEventArgs e)
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            Console.WriteLine("task " + ((TaskEventArgs)e).Id + " done");
坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联    }
坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联


6.两个自定义活动关于关联的相关属性的设置,

 

CreateTask活动和TaskCompleted活动中多了如下属性,给这个关联提供一个唯一的名称.每个分支上的CorrelationToken设置要一致。

坚持学习WF(10):在工作流中使用关联

7.宿主程序:  

坚持学习WF(10):在工作流中使用关联 class WorkflowApplication
坚持学习WF(10):在工作流中使用关联    {
坚持学习WF(10):在工作流中使用关联        static AutoResetEvent waitHandle = new AutoResetEvent(false);
坚持学习WF(10):在工作流中使用关联        static TaskService taskService = new TaskService();
坚持学习WF(10):在工作流中使用关联        static WorkflowInstance instance;
坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        static void Main()
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
坚持学习WF(10):在工作流中使用关联            {
坚持学习WF(10):在工作流中使用关联                ExternalDataExchangeService dataExchangeService = new ExternalDataExchangeService();
坚持学习WF(10):在工作流中使用关联                workflowRuntime.AddService(dataExchangeService);
坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联                dataExchangeService.AddService(taskService);
坚持学习WF(10):在工作流中使用关联                workflowRuntime.StartRuntime();
坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联                workflowRuntime.WorkflowCompleted += OnWorkflowCompleted;
坚持学习WF(10):在工作流中使用关联                workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
坚持学习WF(10):在工作流中使用关联                {
坚持学习WF(10):在工作流中使用关联                    Console.WriteLine(e.Exception.Message);
坚持学习WF(10):在工作流中使用关联                    waitHandle.Set();
坚持学习WF(10):在工作流中使用关联                }
;
坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联                instance = workflowRuntime.CreateWorkflow(typeof(CorrelatedLocalServiceWorkflow));
坚持学习WF(10):在工作流中使用关联                instance.Start();
坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联                waitHandle.WaitOne();
坚持学习WF(10):在工作流中使用关联                workflowRuntime.StopRuntime();
坚持学习WF(10):在工作流中使用关联            }

坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联
坚持学习WF(10):在工作流中使用关联        static void OnWorkflowCompleted(object sender, WorkflowCompletedEventArgs instance)
坚持学习WF(10):在工作流中使用关联        {
坚持学习WF(10):在工作流中使用关联            waitHandle.Set();
坚持学习WF(10):在工作流中使用关联        }

坚持学习WF(10):在工作流中使用关联    }

 

程序运行后结果如下:

坚持学习WF(10):在工作流中使用关联



本文转自生鱼片博客园博客,原文链接:http://www.cnblogs.com/carysun/archive/2008/06/01/WFCorrelation.html,如需转载请自行联系原作者

相关文章:

  • 2021-07-15
  • 2022-01-06
  • 2021-11-17
  • 2021-06-04
  • 2021-08-11
猜你喜欢
  • 2022-03-06
  • 2021-06-14
  • 2021-11-27
相关资源
相似解决方案