通常情況下我們開發的自訂活動的商務邏輯都是寫在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動作。