通常情况下我们开发的自定义活动的业务逻辑都是写在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属性,如图:
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.运行程序执行结果如下:
从结果上我们有的时候会看到WorkItem1和WorkItem2的顺序会颠倒,这是因为我们在本地服务中做了随机的Sleep动作。
发表评论
-
平淡的2007
2007-12-24 08:04 786早上起来,送女朋友去公交车站,然后回来赶紧打开电脑,先 ... -
DreamSpark发布,高校学生免费使用Visual Studio 2008 Professional Edition 等微软软件
2008-02-20 13:23 1384今天上网无意中搜索到学生可以免费使用VS2008专业版,后来又 ... -
坚持学习WF(1):从HelloWorld开始
2008-04-04 16:30 851[置顶]坚持学习WF文章索 ... -
坚持学习WF(2):WF创作模式和设计时工具
2008-04-05 17:19 600[置顶]坚持学习WF文章索 ... -
坚持学习WF(3):WF框架概览
2008-04-08 07:27 740[置顶]坚持学习WF文章索 ... -
坚持学习WF(4):活动(Activity)和依赖属性(DependencyProperty)
2008-04-12 00:01 1105[置顶]坚持学习WF文章索引 活动(Activity) 活动 ... -
坚持学习WF(5):自定义活动(CustomActivity)
2008-04-13 15:25 883当WF提供的标准活动不能满足我们的需求的时候,我们就需要定义自 ... -
MOSS点滴(1):如何开发和部署feature
2008-04-16 21:35 808Features 是MOSS 2007以开箱即用的一套新功能, ... -
MOSS点滴(2):自定义Application Page
2008-04-19 20:07 810在MOSS中后台管理的页面都是Application Pag ... -
坚持学习WF(6):开发可复用的宿主程序
2008-04-21 21:45 664我们之前写工作流宿主 ... -
MOSS点滴(3):说说MOSS中的母版页
2008-04-25 21:15 1139MOSS中有两种页面:Site P ... -
MOSS点滴(4):实现Form认证
2008-04-29 21:12 671本文主要参考了网上的一些文章,但有些文章有些地方说的不是很明确 ... -
坚持学习WF(7):流程控制(Flow Control)
2008-04-30 18:10 776本文主要说说WF中和流 ... -
坚持学习WF(8):本地服务之调用外部方法
2008-05-09 08:17 722WF提供了一组核心服务 ... -
MOSS中的WebPart开发
2008-05-10 13:53 1025由于在asp.net1.1的时候asp.net中还没有webp ... -
坚持学习WF(9):本地服务之事件处理
2008-05-28 07:49 766[置顶]坚持学习WF文章索引 一:先来介绍两个活动 Even ... -
坚持学习WF(10):在工作流中使用关联
2008-06-01 13:03 660[置顶]坚持学习WF文章索 ... -
坚持学习WF(11):工作流通信与队列
2008-06-07 15:45 698[置顶]坚持学习WF文章索引 WF 提供的通信模型是构建于 ... -
MOSS中创建自定义内容类型
2008-06-12 20:23 1072一:简要介绍 某类内容 ... -
.NET中IDisposable接口的基本使用
2008-06-15 12:01 911首先来看MSDN中关于这个接口的说明: [ComVisible ...
相关推荐
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 ...
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架构,整个应用分为jpa实体层、eao层、业务逻辑层、mvc层和视图层,各层之间分层清晰,层与层之间以松耦合的方法组织在一起。该案例既提供了ide无关的、基于ant管理的项目源码...
第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中使用...
第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中使用...
交互者:是演示者将使用的业务包含服务。 单元测试 Mockito:用于模拟对象并控制其行为。 Junit 4 测试主要集中于测试交互器,演示者和解析逻辑。 运行./gradlew test-继续执行测试 已知的问题: 使用...
对于客户机,SessionBean是一种非持久性对象,它实现某些在服务器上运行的业务逻辑。 对于客户机,EntityBean是一种持久性对象,它代表一个存储在持久性存储器中的实体的对象视图,或是一个由现有企业应用程序实现的...
对于客户机,SessionBean是一种非持久性对象,它实现某些在服务器上运行的业务逻辑。 对于客户机,EntityBean是一种持久性对象,它代表一个存储在持久性存储器中的实体的对象视图,或是一个由现有企业应用程序...
将 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 代替 ...
每种类型又是以哪种模式(异步、同步或本地)执行的呢? 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...
2.2.3. 本地方法区(线程私有) ................................................................................................................ 23 2.2.4. 堆(Heap-线程共享)-运行时数据区 .....................