Activity:表示工作流的基本构造块,任意类那样定义一组属性和事件,并定义执行逻辑,这些逻辑定义活动的运行时行为。是所有活动的基类。
所有活动共享一组在 Activity 基类上定义的通用属性。每个 Activity 都可以按照需要,通过扩展此类来声明各自的附加属性。因为 Activity 派生自 DependencyObject,所以属性可以定义为标准 CLR 属性和依赖属性。
此示例定义用于发送电子邮件的活动。该活动定义一个在相应实现中使用依赖属性的 Subject 属性。可以采用类似的方法定义其他属性。对 Execute 方法进行重写,以提供用于发送电子邮件的逻辑。
public class SendEmail : Activity { public static readonly DependencyProperty SubjectProperty = DependencyProperty.Register("Subject", typeof(string), typeof(SendEmail)); public string Subject { get { return base.GetValue(SubjectProperty) as string; } set { base.SetValue(SubjectProperty, value); } } // Define other properties... protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { // Logic to send the e-mail goes here... return ActivityExecutionStatus.Closed; } }
IEventActivity:提供必须从中派生事件驱动活动的方法和属性,以便可以订阅事件。
void Subscribe( ActivityExecutionContext parentContext, IActivityEventListener<QueueEventArgs> parentEventHandler ) //取消订阅 void Unsubscribe( ActivityExecutionContext parentContext, IActivityEventListener<QueueEventArgs> parentEventHandler )
IComparable QueueName { get; } //
获取该活动正在等待其数据到达的 WorkflowQueue 的名称。
源文档 <http://www.cnblogs.com/foundation/archive/2008/06/11/1217345.html?login=1#commentform>
将 IEventActivity 活动放入在 ListenActivity 中时 ,ListenActivity 启动时首先调用 Subscribe 方法,表示开始订阅事件,可在这儿做初始化工作。 当 ListenActivity 活动从消息队列中收到一条消息时,它将调用 Unsubscrible 方法,表示已经收到消息,可在此方法中从消息队列中读取消息| 在ListenActivity中的IEventActivity活动的执行过程为 | Subscribe() Unsubscribe() Execute() |
| 不在ListenActivity中的活动的执行过程为 | Execute() 等待 Queuing 事件 |
当自定义活动作为EventDrivenActivity的一个子活动时,一个事件驱动的活动内部处理过程如下:
Intialize 方法首先被执行,使用户有机会完成内部的任何初始化操作。 定义在 IEventActivity 中的 Sub scribe() 被执行,父活动(比如 ListenActivity 或者是 EventDrivenActivity) 作为 parentEventHandler 参数被传入,使开发人员有机会创建一个命名的工作流队列并且订阅到工作流队列的 QueueItemAbailable 事件。订阅的目的在于通知父活动一个新的消息到达队列。 当一个新的消息到达队列时,父活动得到通知。 Unsubscribe 方法被执行,可以在该方法中从父活动益处事件订阅。 Execute 被执行,此时应该从工作流队列中取出一个消息来执行。当然活动的工作流执行完成时,应该返回活动的状态为 ActivityExcursionStatus.Closed ,指示活动完成。当自定义的事件驱动活动直接放在工作流上时:
Intialize 方法首先被执行 Excute 被执行 新的消息到达队列 后, OnEvent 被执行。IActivityEventListener<QueueEventArgs>
//实现IActivityEventListener<QueueEventArgs> 的[发生订阅事件时的处理过程]事件方法
public void OnEvent(object sender, QueueEventArgs e)
前文中提到的工作流队列先简单说一下:
WF运行时引擎提供了一个内部机制用来处理调度和通信,消息使用一个队列名字被放入一个工作流队列中,并在稍后从队里中取出。压入的消息可以是被序列化的类型。
WF自带的标准事件驱动和ExternalDataExchangeService内部都使用工作流队列来和外部通信,比如当在本地服务中触发一个事件。这个事件被放入一个工作流队列,当HandleExternalEventActivity接收通知,被告之在队列中有一个新的消息可用,该事件将从队里中取出并得以处理。
在工作流实例或者是自定义活动的内部,一个WorkflowQueue类表示一个命名队列。该类实现了一个基本的方法与队列交互,比如Enqueue、peek、Dequeue等。还有当一个新的消息可用于处理时,触发QueueItemAvailable事件,或者当一个队列中的消息传送过来时,可处理QueueItemArrived事件。
//获取WorkflowQueueingService对象的实例 // 是工作流运行时内置的一个工作流服务。 WorkflowQueuingService qService = context.GetService<WorkflowQueuingService>(); if (qService.Exists(this.QueueName)) //如果存在指定名称的队列,则获取该队列 return qService.GetWorkflowQueue(this.QueueName); else //否则创建一个新的队列 return qService.CreateWorkflowQueue(this.QueueName, true);
宿主应用程序或本地服务可以向队列中加入消息以便让工作流实例使用。这是通过使用WorkflowInstance类的EnqueueItem或者EnqueueItemIdle()方法实现的。
深入了解一下IEventActivity和IActivityEventListener:事件驱动的活动有些特别,因为其并不是立即就得执行,而是通过注册一个事件,然后等待事件的触发。为了定义一个事件驱动的活动,应该实现IEventActivity接口。该接口定义了一个事件驱动活动的必须实现的契约。定义了Subscribe和Unsubscribe方法用于处理事件注册过程。这些方法被当前活动的父活动所利用。Subscribe和Unsubscribe方法传递了一个实现了IActivityEventListener接口的对象。IEventActivity也定义了一个名为QueueName的属性用于返回活动将用于接收消息的队列的名称。
IEventActivity并没有定义如何接受事件通知,留给了IActivityEventListener接口来实现。因此一个事件驱动的活动应该也要实现IActivityEventListener接口。IActivityEventListener定义了一个OnEvent()方法,当一个新的事件被接收并用于处理时,调用该方法。当开发一个基于队列的事件驱动活动时,事件参数应该总是类型QueueEventArgs。
一般情况下,一个事件驱动的活动都被放在EventDrivenAcitivity中(或者有一个ListenActivity和EventDrivenActivity组成的复合活动),然而,一个自定义的事件驱动的活动也可以直接被用于工作流中,使其在EventDrivenActivity的外面。
自定义的Activity
public class Activity1 : Activity, IActivityEventListener<QueueEventArgs>, IEventActivity { public string Text { set; get; } protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { if (myProcessAEC(executionContext)) { return ActivityExecutionStatus.Closed; } else { Subscribe(executionContext, this); return ActivityExecutionStatus.Executing; } } private bool myProcessAEC(ActivityExecutionContext provider) { WorkflowQueuingService queueService = provider.GetService<WorkflowQueuingService>(); if (queueService.Exists(this.QueueName) && queueService.GetWorkflowQueue(this.QueueName).Count > 0) { object inputData = queueService.GetWorkflowQueue(this.QueueName).Dequeue(); System.Console.WriteLine("外部传入的数据:" + inputData.ToString()); 通信接口 obj = provider.GetService<通信接口>(); this.Text = obj.Text; return true; } return false; } //实现IActivityEventListener<QueueEventArgs> 的[发生订阅事件时的处理过程]事件方法 public void OnEvent(object sender, QueueEventArgs e) { ActivityExecutionContext aec = sender as ActivityExecutionContext; if (myProcessAEC(aec)) { Unsubscribe(aec, this); aec.CloseActivity(); } } //实现IEventActivity的[WorkflowQueue名称]属性 public IComparable QueueName { get { return this.QualifiedName; } } //实现IEventActivity的[事件的订阅]方法 public void Subscribe(ActivityExecutionContext parentContext, IActivityEventListener<QueueEventArgs> parentEventHandler) { WorkflowQueuingService queueService = parentContext.GetService<WorkflowQueuingService>(); if (queueService != null && !queueService.Exists(this.QueueName)) { WorkflowQueue queue = queueService.CreateWorkflowQueue(this.QueueName, false); queue.RegisterForQueueItemAvailable(parentEventHandler); 通信接口 obj = parentContext.GetService<通信接口>(); if (obj != null) { obj.QueueName = this.QueueName; obj.myTest(Text); obj.Text=this.Text; } } } //实现IEventActivity的[取消事件的订阅]方法 public void Unsubscribe(ActivityExecutionContext parentContext, IActivityEventListener<QueueEventArgs> parentEventHandler) { WorkflowQueuingService queueService = parentContext.GetService<WorkflowQueuingService>(); if (queueService != null && queueService.Exists(this.QueueName)) { queueService.GetWorkflowQueue(this.QueueName).UnregisterForQueueItemAvailable(parentEventHandler); queueService.DeleteWorkflowQueue(this.QueueName); } } }
例子
WF事件驱动活动解析
本文详细介绍了WF中事件驱动活动的实现方式,包括Activity基类的功能特性、IEventActivity接口的作用及其实现方法,以及如何通过自定义活动实现事件监听与处理。
19万+

被折叠的 条评论
为什么被折叠?



