天天看點

堅持學習WF(10):在工作流中使用關聯

<a href="http://www.cnblogs.com/carysun/archive/2008/05/29/WF.html">[置頂]堅持學習WF文章索引</a>

一:當我們在工作流中使用本地服務的事件的時候,WF運作時引擎将入站消息映射到執行個體中的特定的HandleExternalEventActivity活動,對執行個體的映射是在将工作流執行個體InstanceId傳遞到ExternalDataEventArgs構造函數時完成的。是以當工作流執行個體在本地服務接口上偵聽相同僚件的不同執行個體時,就無法确定該響應哪個事件。如下圖:

<a href="http://www.cnblogs.com/images/cnblogs_com/carysun/WindowsLiveWriter/WF10_13A4C/correlation4.jpg"></a>

如何解決這個問題呢,我們就需要在工作流中使用關聯,通過使用接口屬性來定義關聯,使用關聯後通信活動會多出一個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&lt;TaskEventArgs&gt; TaskCompleted;

堅持學習WF(10):在工作流中使用關聯

注意:2.1 [CorrelationParameter("taskId")] 中的"taskId"和CreateTask方法中的string taskId要一緻。

           2.2 [CorrelationAlias("taskId", "e.Id")] 關聯參數的别名綁定。 

堅持學習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&lt;TaskEventArgs&gt; 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&lt;TaskEventArgs&gt; 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):在工作流中使用關聯
堅持學習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):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯

        public string TaskId

堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯

                return ((string)(base.GetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.TaskIdProperty)));

堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯

                base.SetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.TaskIdProperty, value);

堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯

                return ((string)(base.GetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.TextProperty)));

堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習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):在工作流中使用關聯
堅持學習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):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯

        public object Sender

堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯

                return ((Object)(base.GetValue(TaskCompleted.SenderProperty)));

堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習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):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯

        public Microsoft.Samples.Workflow.CorrelatedLocalService.TaskEventArgs EventArgs

堅持學習WF(10):在工作流中使用關聯

              {

堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯

                return ((TaskEventArgs)(base.GetValue(TaskCompleted.EventArgsProperty)));

堅持學習WF(10):在工作流中使用關聯
堅持學習WF(10):在工作流中使用關聯
堅持學習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設定要一緻。

<a href="http://www.cnblogs.com/images/cnblogs_com/carysun/WindowsLiveWriter/WF10_13A4C/correlation2.jpg"></a>

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):在工作流中使用關聯

程式運作後結果如下:

<a href="http://www.cnblogs.com/images/cnblogs_com/carysun/WindowsLiveWriter/WF10_13A4C/correlation3.jpg"></a>

本文轉自生魚片部落格園部落格,原文連結:http://www.cnblogs.com/carysun/archive/2008/06/01/WFCorrelation.html,如需轉載請自行聯系原作者

繼續閱讀