狀态機工作流是為事件驅動的工作場景設計的。一個狀态機工作流包含兩個或兩個以上的狀态,且任意時刻隻有一個處于激活狀态。在這一節中,我們将建立一個基于狀态機的工作流,這個工作流将通過其内部不同的狀态,來處理宿主程式送出的訂單。初始狀态為WaitForOrderState,隻要宿主程式送出了一個新訂單,這個狀态就會執行。當收到一個新訂單後,進入OrderProcessing狀态開始處理訂單。最後一個狀态就是OrderCompletedState。在這個過程中,不同的狀态将會與宿主程式互動。 建立一個狀态機工作流 一個狀态機工作流可以繼承從StateMachineWorkflow類,這個類中已經實作了狀态機工作流的大部分功能。一旦你繼承了這個類,你就可以開始在工作流中加入所需的狀态,并使用SetState活動或事件驅動的活動如EventSink把這些狀态連接配接起來。以下的代碼就是我們的工作流類OrderProcessingWorkflow,這個類是接下來整個示例程式的基礎。你可能已經注意到了,類中聲明了兩個變量。這兩個變量是用來存貯目前訂單資訊的,這些資訊将會在整個流程中用到。
using System;
using System.Workflow.ComponentModel;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
namespace Microsoft.Samples.Workflow.Quickstarts.StateMachine
{
public partial class OrderProcessingWorkflow : StateMachineWorkflow
{
private string orderId;
private string itemStatus;
public OrderProcessingWorkflow()
{
InitializeComponent();
}
private void InitializeComponent()
{
}
}
}
建立活動和參數綁定 WWF中有兩個類ActivityBind和ParameterBinding,是專門用來将活動中的變量,綁定到方法調用所需的參數上的。這個方法定義在一個接口中,接口的實作就是注冊到工作流中的服務。在我們的程式中,我們将把目前訂單的orderId和status的值傳遞進去。以下的代碼示例了如何建立和聯系工作流的私有變量和參數。這些參數将用來根據目前工作流的狀态來更新宿主。在稍後建立狀态活動時,我們将用到這些綁定對象。 開始建立活動和參數綁定 1. 定義一個私有變量
類型 | 名稱 |
ActivityBind | orderIdActivityBind |
ParameterBinding | orderIdParameterBinding |
ActivityBind | itemStatusActivityBind |
ParameterBinding | itemStatusParameterBinding |
2. 以下代碼示例了如何建立ActivityBind和ParameterBinding,以及怎樣和私有變量綁定。
//
// Binding variables
//
orderIdActivityBind = new ActivityBind();
orderIdParameterBinding = new ParameterBinding();
itemStatusActivityBind = new ActivityBind();
itemStatusParameterBinding = new ParameterBinding();
orderIdActivityBind.ID = " /Workflow " ;
orderIdActivityBind.Path = " orderId " ;
orderIdParameterBinding.ParameterName = " orderId " ;
orderIdParameterBinding.SetBinding(System.Workflow.ComponentModel.ParameterBinding.ValueProperty,
((System.Workflow.ComponentModel.Bind)(orderIdActivityBind)));
itemStatusActivityBind.ID = " /Workflow " ;
itemStatusActivityBind.Path = " itemStatus " ;
itemStatusParameterBinding.ParameterName = " newStatus " ;
itemStatusParameterBinding.SetBinding(System.Workflow.ComponentModel.ParameterBinding.ValueProperty,
((System.Workflow.ComponentModel.Bind)(itemStatusActivityBind))); 構造WaitingForOrder狀态 這第一個狀态監聽來自宿主的事件,這個事件通知工作流一個新的訂單已經被送出了,應該馬上處理它。當你建立狀态時,狀态的第一個子活動必須是StateInitialization活動或實作了IEventActivity接口的活動。這裡的WaitForOrderState采用了後者,因為這個狀态是由宿主程式的事件激活的。 EventSink活動是用來監聽注冊在WWF運作庫中的服務的事件的,在我們的程式中,這個服務由宿主程式提供。我們在工作流中定義了IOrderingService接口,這個接口稍後将由宿主程式實作。
using System;
using System.Workflow.ComponentModel;
using System.Workflow.Runtime.Messaging;
namespace Microsoft.Samples.Workflow.Quickstarts.StateMachine
{
[Serializable]
public class NewOrderEventArgs : WorkflowMessageEventArgs
{
private string item;
private int quantity;
public NewOrderEventArgs(Guid instanceId, string item, int quantity)
: base(instanceId)
{
this.item = item;
this.quantity = quantity;
}
public string Item
{
get
{ return item; }
set
{ item = value; }
}
public int Quantity
{
get
{ return quantity; }
set
{ quantity = value; }
}
}
[DataExchangeService]
public interface IOrderingService
{
void ItemStatusUpdate( string orderId, string newStatus);
event EventHandler<NewOrderEventArgs> NewOrder;
}
} 一旦EventSink活動處理了觸發事件後,一個狀态消息需要通過IOrderingInterface發回宿主程式。工作流需要調用接口中的ItemStatusUpdate方法,并傳遞orderId和newStatues參數。而調用接口方法的工作,就交給InvokeMethodActivity活動了。我們指定活動的InterfaceType參數為我們需要的服務接口,MethodName屬性設為要調用的服務接口中的方法名稱,然後在ParameterBindings中加入之前構造好的參數綁定,最後為活動的MethodInvoking事件指定一個事件處理程式,用來改變目前訂單的狀态。因為我們已經把orderId和newStatus參數綁定到了私有變量orderId和itemStatus上,是以為ItemStatusUpdate方法傳遞參數的過程是由WWF運作庫自動完成的。 更新完成之後,WaitingForOrderState狀态已經準備好轉移下一個狀态——OrderOpenState(譯者注:這裡錯了,應該是OrderPrecessingState)狀态。SetState活動是專門負責狀态轉移的。把一個SetState活動加入到EventDriven的最後一環,當一切處理完後,SetState活動将執行,并立馬跳轉到指定的下一個狀态。 開始構造WaitForOrderState 1. 定義5個私有變量
類型 | 名稱 |
EventSinkActivity | newOrderEventSink |
InvokeMethodActivity | updatestatusOrderReceived |
SetState | setStateOrderProcessing |
EventDriven | eventDriven1 |
State | WaitingForOrderState |
2. 用預設構造函數執行個體化以上變量 以下代碼示範了如何構造WaitForOrderState。先是EventSinkActivity來處理宿主事件,然後InvokeMethodActivity來改變目前訂單狀态,并更新宿主狀态。最後,SetState活動将WaitForOrder狀态轉移到OrderPrecessing狀态。把這三個活動就依次加入到EventDriven活動的子活動中。
//
// WaitingForOrder State
//
this .newOrderEventSink = new System.Workflow.Activities.EventSinkActivity();
this .newOrderEventSink.EventName = " NewOrder " ;
this .newOrderEventSink.ID = " newOrderEventSink " ;
this .newOrderEventSink.InterfaceType = typeof (Microsoft.Samples.Workflow.Quickstarts.StateMachine.IOrderingService);
this .newOrderEventSink.Roles = null ;
this .updatestatusOrderReceived = new System.Workflow.Activities.InvokeMethodActivity();
this .updatestatusOrderReceived.ID = " updatestatusOrderReceived " ;
this .updatestatusOrderReceived.InterfaceType = typeof (Microsoft.Samples.Workflow.Quickstarts.StateMachine.IOrderingService);
this .updatestatusOrderReceived.MethodName = " ItemStatusUpdate " ;
this .updatestatusOrderReceived.ParameterBindings.Add(orderIdParameterBinding);
this .updatestatusOrderReceived.ParameterBindings.Add(itemStatusParameterBinding);
this .updatestatusOrderReceived.MethodInvoking += new System.EventHandler( this .OrderReceived);
this .setStateOrderProcessing = new System.Workflow.Activities.SetState();
this .setStateOrderProcessing.ID = " setStateOrderProcessing " ;
this .setStateOrderProcessing.TargetState = " OrderProcessingState " ;
this .eventDriven1 = new System.Workflow.Activities.EventDriven();
this .eventDriven1.Activities.Add( this .newOrderEventSink);
this .eventDriven1.Activities.Add( this .updatestatusOrderReceived);
this .eventDriven1.Activities.Add( this .setStateOrderProcessing);
this .eventDriven1.ID = " eventDriven1 " ;
this .WaitingForOrderState = new System.Workflow.Activities.State();
this .WaitingForOrderState.Activities.Add( this .eventDriven1);
this .WaitingForOrderState.ID = " WaitingForOrderState " ; 你可以在InvokeMethodActivity活動執行的前一刻,加入一些附加的邏輯。隻要為MethodInvoking事件指定一個處理程式,就能做到這一點。以下的代碼就是MethodInvoking事件的處理程式。它為itemStatus和orderId變量指定了新的值。事件處理程式的指定,已經在上面的代碼中做了。
private void OrderReceived( object sender, EventArgs e)
{
itemStatus = "Received order";
orderId = Guid.NewGuid().ToString();
}