`

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

阅读更多

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

分享到:
评论

相关推荐

    ASP.NET 控件的使用

    15.3.3 创建业务逻辑层 492 15.3.4 创建数据访问层 494 15.4 小结 497 第16章 使用ObjectDataSource控件 498 16.1 使用ObjectDataSource控件表示对象 498 16.1.1 绑定到组件 499 16.1.2 绑定到DataReader 500 ...

    ASP.NET.4揭秘

    17.3.3 创建业务逻辑层584 17.3.4 创建数据访问层587 17.4 小结591 第18章 使用objectdatasource 控件592 18.1 使用objectdatasource控件表示对象592 18.1.1 绑定到组件593 18.1.2 绑定到datareader594 18.1.3 绑定...

    经典JAVA.EE企业应用实战.基于WEBLOGIC_JBOSS的JSF_EJB3_JPA整合开发.pdf

    该案例采用目前最流行、最规范的java ee架构,整个应用分为jpa实体层、eao层、业务逻辑层、mvc层和视图层,各层之间分层清晰,层与层之间以松耦合的方法组织在一起。该案例既提供了ide无关的、基于ant管理的项目源码...

    Spring.3.x企业应用开发实战(完整版).part2

    第13章 任务调度和异步执行器 13.1 任务调度概述 13.2 Quartz快速进阶 13.2.1 Quartz基础结构 13.2.2 使用SimpleTrigger 13.2.3 使用CronTrigger 13.2.4 使用Calendar 13.2.5 任务调度信息存储 13.3 在Spring中使用...

    Spring3.x企业应用开发实战(完整版) part1

    第13章 任务调度和异步执行器 13.1 任务调度概述 13.2 Quartz快速进阶 13.2.1 Quartz基础结构 13.2.2 使用SimpleTrigger 13.2.3 使用CronTrigger 13.2.4 使用Calendar 13.2.5 任务调度信息存储 13.3 在Spring中使用...

    message-parser-android

    交互者:是演示​​者将使用的业务包含服务。 单元测试 Mockito:用于模拟对象并控制其行为。 Junit 4 测试主要集中于测试交互器,演示者和解析逻辑。 运行./gradlew test-继续执行测试 已知的问题: 使用...

    java 面试题 总结

    对于客户机,SessionBean是一种非持久性对象,它实现某些在服务器上运行的业务逻辑。 对于客户机,EntityBean是一种持久性对象,它代表一个存储在持久性存储器中的实体的对象视图,或是一个由现有企业应用程序实现的...

    超级有影响力霸气的Java面试题大全文档

     对于客户机,SessionBean是一种非持久性对象,它实现某些在服务器上运行的业务逻辑。  对于客户机,EntityBean是一种持久性对象,它代表一个存储在持久性存储器中的实体的对象视图,或是一个由现有企业应用程序...

    asp.net知识库

    将 ASP.NET 2.0 应用程序服务配置为使用 SQL Server 2000 或 SQL Server 2005 ASP.NET 2.0 中的数据源控件 使用 ASP.NET 2.0 ObjectDataSource 控件 ASP.NET 2.0 的内部变化 使用SQL Cache Dependency 代替 ...

    ABAP面试大全

    每种类型又是以哪种模式(异步、同步或本地)执行的呢? 11 2.2.7使用OPEN SQL注意原则 11 2.3 与表相关 11 2.3.1 MM模块有哪些常用表格 11 2.3.2 HR模块知识:HR里面存储HR主数据主要用到了哪些表? 11 2.3.3 HR...

    JAVA核心知识点整理(有效)

    2.2.3. 本地方法区(线程私有) ................................................................................................................ 23 2.2.4. 堆(Heap-线程共享)-运行时数据区 .....................

Global site tag (gtag.js) - Google Analytics