<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:
[Serializable]
public class TaskEventArgs : ExternalDataEventArgs
{
string idValue;
string assigneeValue;
string textValue;
public TaskEventArgs(Guid instanceId, string id, string assignee, string text)
:base(instanceId)
{
this.idValue = id;
this.assigneeValue = assignee;
this.textValue = text;
}
public string Id
get { return this.idValue; }
set { this.idValue = value; }
public string Assignee
get { return this.assigneeValue; }
set { this.assigneeValue = value; }
public string Text
get { return this.textValue; }
set { this.textValue = value; }
}
2.定義服務接口:
[ExternalDataExchange]
[CorrelationParameter("taskId")]
public interface ITaskService
{
[CorrelationInitializer]
void CreateTask(string taskId, string assignee, string text);
[CorrelationAlias("taskId", "e.Id")]
event EventHandler<TaskEventArgs> TaskCompleted;
注意:2.1 [CorrelationParameter("taskId")] 中的"taskId"和CreateTask方法中的string taskId要一緻。
2.2 [CorrelationAlias("taskId", "e.Id")] 關聯參數的别名綁定。
public class TaskService : ITaskService
public void CreateTask(string taskId, string assignee, string text)
Console.WriteLine("task " + taskId + " created for " + assignee);
ThreadPool.QueueUserWorkItem(ShowDialog, new TaskEventArgs(WorkflowEnvironment.WorkflowInstanceId, taskId, assignee, text));
public void RaiseEvent(TaskEventArgs args)
EventHandler<TaskEventArgs> taskCompleted = this.TaskCompleted;
if (taskCompleted != null)
taskCompleted(null, args);
public void ShowDialog(object state)
TaskEventArgs taskEventArgs = state as TaskEventArgs;
MessageBox.Show(string.Format("{0}, click OK when '{1}' completed.", taskEventArgs.Assignee, taskEventArgs.Text), string.Format("Task {0}", taskEventArgs.Id), MessageBoxButtons.OK);
RaiseEvent(taskEventArgs);
public event EventHandler<TaskEventArgs> TaskCompleted;
4.建立自定義通信活動
4.1 CreateTask活動繼承自CallExternalMethodActivity,來調用本地服務中的方法,在構造函數中設定InterfaceType和MethodName屬性。代碼如下:
[ToolboxItemAttribute(typeof(ActivityToolboxItem))]
public partial class CreateTask : System.Workflow.Activities.CallExternalMethodActivity
// Properties on the task
public static DependencyProperty AssigneeProperty = DependencyProperty.Register("Assignee", typeof(System.String), typeof(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask));
public static DependencyProperty TaskIdProperty = DependencyProperty.Register("TaskId", typeof(System.String), typeof(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask));
public static DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(System.String), typeof(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask));
private void InitializeComponent()
public CreateTask()
this.InterfaceType = typeof(Microsoft.Samples.Workflow.CorrelatedLocalService.ITaskService);
this.MethodName = "CreateTask";
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
[BrowsableAttribute(true)]
get
{
return ((string)(base.GetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.AssigneeProperty)));
}
set
base.SetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.AssigneeProperty, value);
public string TaskId
return ((string)(base.GetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.TaskIdProperty)));
base.SetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.TaskIdProperty, value);
return ((string)(base.GetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.TextProperty)));
base.SetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.TextProperty, value);
protected override void OnMethodInvoking(EventArgs e)
this.ParameterBindings["taskId"].Value = this.TaskId;
this.ParameterBindings["assignee"].Value = this.Assignee;
this.ParameterBindings["text"].Value = this.Text;
4.2 TaskCompleted活動繼承自HandleExternalEventActivity,來處理本地服務中的事件,在構造函數中設定
InterfaceType和EventName屬性。代碼如下:
public partial class TaskCompleted : System.Workflow.Activities.HandleExternalEventActivity
// properties
public static DependencyProperty SenderProperty = System.Workflow.ComponentModel.DependencyProperty.Register("Sender", typeof(Object), typeof(TaskCompleted));
public static DependencyProperty EProperty = System.Workflow.ComponentModel.DependencyProperty.Register("E", typeof(TaskEventArgs), typeof(TaskCompleted));
public TaskCompleted()
this.EventName = "TaskCompleted";
public object Sender
return ((Object)(base.GetValue(TaskCompleted.SenderProperty)));
base.SetValue(TaskCompleted.SenderProperty, value);
public static DependencyProperty EventArgsProperty = System.Workflow.ComponentModel.DependencyProperty.Register("EventArgs", typeof(TaskEventArgs), typeof(TaskCompleted));
public Microsoft.Samples.Workflow.CorrelatedLocalService.TaskEventArgs EventArgs
{
return ((TaskEventArgs)(base.GetValue(TaskCompleted.EventArgsProperty)));
base.SetValue(TaskCompleted.EventArgsProperty, value);
protected override void OnInvoked(EventArgs e)
EventArgs = e as TaskEventArgs;
5.實作工作流如下圖:
public sealed partial class CorrelatedLocalServiceWorkflow : SequentialWorkflowActivity
public CorrelatedLocalServiceWorkflow()
InitializeComponent();
}
private void OnTaskCompleted(object sender, ExternalDataEventArgs e)
Console.WriteLine("task " + ((TaskEventArgs)e).Id + " done");
6.兩個自定義活動關于關聯的相關屬性的設定,
CreateTask活動和TaskCompleted活動中多了如下屬性,給這個關聯提供一個唯一的名稱.每個分支上的CorrelationToken設定要一緻。
<a href="http://www.cnblogs.com/images/cnblogs_com/carysun/WindowsLiveWriter/WF10_13A4C/correlation2.jpg"></a>
7.宿主程式:
class WorkflowApplication
static AutoResetEvent waitHandle = new AutoResetEvent(false);
static TaskService taskService = new TaskService();
static WorkflowInstance instance;
static void Main()
using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
ExternalDataExchangeService dataExchangeService = new ExternalDataExchangeService();
workflowRuntime.AddService(dataExchangeService);
dataExchangeService.AddService(taskService);
workflowRuntime.StartRuntime();
workflowRuntime.WorkflowCompleted += OnWorkflowCompleted;
workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Message);
waitHandle.Set();
};
instance = workflowRuntime.CreateWorkflow(typeof(CorrelatedLocalServiceWorkflow));
instance.Start();
waitHandle.WaitOne();
workflowRuntime.StopRuntime();
static void OnWorkflowCompleted(object sender, WorkflowCompletedEventArgs instance)
waitHandle.Set();
程式運作後結果如下:
<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,如需轉載請自行聯系原作者