博客园  :: 首页  :: 联系 :: 订阅 订阅  :: 管理

使用本地服务异步执行自定义活动业务逻辑

Posted on 2008-11-01 14:25  生鱼片  阅读(1599)  评论(1编辑  收藏  举报

通常情况下我们开发的自定义活动的业务逻辑都是写在Execte方法中的,由于一个工作流实例在单一的线程上执行,这样当工作流在执行到这个活动的时候,该活动就独占了整个工作流的线程,如果该自定义活动需要做很长时间的任务,那么此时就不能处理工作流中的其他请求。所以我们不建议把所有的业务逻辑都放到Execute方法中去执行。

1.我们可以将活动的业务逻辑放到本地服务中去异步执行,下面我们用一个例子来说明,建立一个顺序型工作流控制台项目,首先我们先写两个类CaryWork和CaryWorkResult,分别代表我们要执行的工作项和返回的结果,代码如下:

[Serializable]
public class CaryWork
{
    public Guid InstanceId { get; set; }
    public String WorkItem { get; set; }
    public String ResultQueueName { get; set; }

    public CaryWork( Guid InstanceId, String ResultQueueName, String WorkItem)
    {
        this.InstanceId = InstanceId;
        this.ResultQueueName = ResultQueueName;
        this.WorkItem = WorkItem;
    }
}
[Serializable]
public class CaryWorkResult
{
   public String Result { get; set; }
public CaryWorkResult(String Result) { this.Result = Result; } }

ResultQueueName 表示返回结果的队列名称。
InstanceId表示工作流的id
WorkItem 表示要执行的任务


2.然后我们开始编写本地服务的部分,首先声明一个接口,接口中的方法将会在自定义活动中调用,代码如下:
public interface ILongTaskServices
{
   voidDoLongTaskWork(CaryWorkworkToDo);
}

然后实现该接口,代码如下:

public class LongTaskServices : WorkflowRuntimeService,ILongTaskServices
{
   private Random _random = new Random();

   public void DoLongTaskWork(CaryWork workToDo)
   {
       ThreadPool.QueueUserWorkItem(TPWorkCallback, workToDo);
       Console.WriteLine("工作项队列: {0}",workToDo.WorkItem);
   }       

   private void TPWorkCallback(Object state)
   {
       CaryWork workitem = state as CaryWork;
       WorkflowInstance instance = Runtime.GetWorkflow(workitem.InstanceId);            
       Int32 msw = _random.Next(1000, 5000);
       Thread.Sleep(msw);
       CaryWorkResult response = new CaryWorkResult(String.Format(
"工作项-{0}返回-{1}", workitem.WorkItem, msw)); instance.EnqueueItem(workitem.ResultQueueName, response, null, null); } }
在本地服务中我们使用线程池来执行我们要完成的任务,我们使用Thread的Sleep方法假定每项任务要执行的时间,完
成后会返回CaryWorkResult对象。
 
3.现在我们实现我们的自定义活动,代码如下:
public partial class LongTaskActivity : Activity,IActivityEventListener<QueueEventArgs>
{
public static DependencyProperty WorkItemProperty = DependencyProperty.Register("WorkItem", typeof(string), typeof(LongTaskActivity)); [DescriptionAttribute("WorkItem")] [BrowsableAttribute(true)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] public string WorkItem { get{ return ((string)(base.GetValue(LongTaskActivity.WorkItemProperty)));} set{ base.SetValue(LongTaskActivity.WorkItemProperty, value);} } private String queueName = Guid.NewGuid().ToString(); public LongTaskActivity() { InitializeComponent(); } protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { ILongTaskServices longRunningService=executionContext.GetService(typeof
(ILongTaskServices)) as ILongTaskServices; WorkflowQueuingService queueService= executionContext.GetService(typeof
(WorkflowQueuingService))as WorkflowQueuingService;
WorkflowQueue queue = queueService.CreateWorkflowQueue(queueName, true); queue.RegisterForQueueItemAvailable(this); CaryWork request = new CaryWork(this.WorkflowInstanceId, queueName, WorkItem); Console.WriteLine("调用本地服务: {0}", WorkItem); longRunningService.DoLongTaskWork(request); return ActivityExecutionStatus.Executing; } public void OnEvent(object sender, QueueEventArgs e) { ActivityExecutionContext aec = sender as ActivityExecutionContext; WorkflowQueuingService queueService = aec.GetService<WorkflowQueuingService>(); WorkflowQueue queue = queueService.GetWorkflowQueue(e.QueueName); if (queue != null && queue.Count > 0) { CaryWorkResult response = queue.Dequeue() as CaryWorkResult; if (response != null) Console.WriteLine("结果为: {0}", response.Result); } queueService.DeleteWorkflowQueue(e.QueueName); aec.CloseActivity(); }
}
在自定义活动中我们去调用本地服务的方法来执行工作项,queue工作流队列被创建,Execute方法中返回
ActivityExecutionStatus.Executing表示工作项没有执行完成,完成后会在OnEvent事件中向控制台输出结果,并调
用AEC的CloseActivity方法来关闭活动。
 
4.设计工作流,我们在工作流设计器中拖一个ParallelActivity活动,并向每个分支中拖入一个我们自定义的活动,
并设置其WorkItem属性,如图:
ActivitLocalService2 
 
5.在宿主程序我们需要加载本地服务到工作流引擎中,代码如下:
static void Main(string[] args)
{
    using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
    {
        AutoResetEvent waitHandle = new AutoResetEvent(false);
        workflowRuntime.WorkflowCompleted += delegate(object sender,WorkflowCompletedEventArgs e)
{waitHandle.Set();}; workflowRuntime.WorkflowTerminated+=delegate(object sender,WorkflowTerminatedEventArgs e) { Console.WriteLine(e.Exception.Message); waitHandle.Set(); }; workflowRuntime.AddService(new LongTaskServices()); WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof
(CaryLongWF.LongTaskWorkflow)); Console.WriteLine("---工作流执行开始---"); instance.Start(); waitHandle.WaitOne(); Console.WriteLine("---工作流执行结束---"); } }
 
6.运行程序执行结果如下:

ActivitLocalService1 

从结果上我们有的时候会看到WorkItem1和WorkItem2的顺序会颠倒,这是因为我们在本地服务中做了随机的Sleep动作。