zoukankan      html  css  js  c++  java
  • 使用本地服务异步执行自定义活动业务逻辑

    通常情况下我们开发的自定义活动的业务逻辑都是写在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动作。

    作者:生鱼片
             
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    java 基本数据类型的取值范围
    警惕自增的陷阱
    三元操作符的类型务必一致
    不要随便设置随机种子
    优先使用整形池
    IN、ANY、ALL与SOME
    第六章-序列:字符串、列表和元组 笔记
    第十二章-安全性
    第五章-数字 课后答案
    第十一章-约束、视图与事务
  • 原文地址:https://www.cnblogs.com/carysun/p/LongActivity.html
Copyright © 2011-2022 走看看