UML软件工程组织

 

 

Windows Workflow Foundation之旅(二)
 
作者:wolf's cave 文章来源:CSDN
 

Windows workflow foundation之旅(三)——指南2(创建状态机工作流)(上)

翻译自:ms-help://MS.WinWF.v1.EN/WinWF_GettingStarted/html/8b6344bc-c879-41c5-babf-74e91c34d281.htm

状态机工作流是为事件驱动的工作场景设计的。一个状态机工作流包含两个或两个以上的状态,且任意时刻只有一个处于激活状态。在这一节中,我们将创建一个基于状态机的工作流,这个工作流将通过其内部不同的状态,来处理宿主程序提交的订单。初始状态为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();
}

Windows workflow foundation之旅(四)——指南2(创建状态机工作流)(下)

翻译自:ms-help://MS.WinWF.v1.EN/WinWF_GettingStarted/html/8b6344bc-c879-41c5-babf-74e91c34d281.htm

构造OrderProcessing状态

我们这个工作流的下一个状态就是OrderProcessingState。在这个状态中,工作流已经收到了订单,并准备好处理了。这个状态和上一个状态最大的不同就是激活方式。WaitForOrderState状态是宿主程序触发一个事件激活的,这个事件通知工作流一个新的订单需要被处理。而在OrderProcessingState状态是上一个状态由SetState转移而激活的。

这个例子中,我们只是简单的给宿主程序发送一个消息,告诉它定单已经处理完了。但实际情况会复杂的多。在宿主程序更新完订单状态之后,我们使用SetState活动,把状态转移到这个工作流的最后一个状态。

在上一个状态中,状态直到收到了一个宿主事件后才开始执行,在这之前,状态机是空闲的。而这个状态则是立即开始执行的。立即执行的状态需要使用StateInitialization活动。这个活动是一种组件活动(类似EventDriven),但它是当状态一激活就立即执行的。

开始构建OrderProcessingState

1. 定义5个私有变量

类型
名称
InvokeMethodActivity
invokeProcessingNewOrderStatusUpdate
InvokeMethodActivity
invokeOrderProcessedStatusUpdate
SetState setStateOrderCompleted
StateInitialization initializeOrderProcessingState
State OrderProcessingState

2. 用默认构造函数实例化。

以下的代码演示了如何构造一个OrderProcessingState。两个InvokeMethodActivity分别更新宿主程序的状态,SetState活动把控制权转移到最后一个状态。

//

// OrderProcessing State

//

this.invokeProcessingNewOrderStatusUpdate = new System.Workflow.Activities.InvokeMethodActivity();

this.invokeProcessingNewOrderStatusUpdate.ID = "invokeProcessingNewOrderStatusUpdate";

this.invokeProcessingNewOrderStatusUpdate.InterfaceType = typeof(Microsoft.Samples.Workflow.Quickstarts.StateMachine.IOrderingService);

this.invokeProcessingNewOrderStatusUpdate.MethodName = "ItemStatusUpdate";

this.invokeProcessingNewOrderStatusUpdate.ParameterBindings.Add(orderIdParameterBinding);

this.invokeProcessingNewOrderStatusUpdate.ParameterBindings.Add(itemStatusParameterBinding);

this.invokeProcessingNewOrderStatusUpdate.MethodInvoking +=

    new System.EventHandler(this.ProcessNewOrder);

 

this.invokeOrderProcessedStatusUpdate = new System.Workflow.Activities.InvokeMethodActivity();

this.invokeOrderProcessedStatusUpdate.ID = "invokeOrderProcessedStatusUpdate";

this.invokeOrderProcessedStatusUpdate.InterfaceType = typeof(Microsoft.Samples.Workflow.Quickstarts.StateMachine.IOrderingService);

this.invokeOrderProcessedStatusUpdate.MethodName = "ItemStatusUpdate";

this.invokeOrderProcessedStatusUpdate.ParameterBindings.Add(orderIdParameterBinding);

this.invokeOrderProcessedStatusUpdate.ParameterBindings.Add(itemStatusParameterBinding);

this.invokeOrderProcessedStatusUpdate.MethodInvoking += new EventHandler(FinalizeOrder);

 

this.setStateOrderCompleted = new System.Workflow.Activities.SetState();

this.setStateOrderCompleted.ID = "setStateOrderCompleted";

this.setStateOrderCompleted.TargetState = "OrderCompletedState";

 

this.initializeOrderProcessingState = new System.Workflow.Activities.StateInitialization();

this.initializeOrderProcessingState.Activities.Add(this.invokeProcessingNewOrderStatusUpdate);

this.initializeOrderProcessingState.Activities.Add(this.invokeOrderProcessedStatusUpdate);

this.initializeOrderProcessingState.Activities.Add(this.setStateOrderCompleted);

this.initializeOrderProcessingState.ID = "initializeOrderOpenState";

 

this.OrderProcessingState = new System.Workflow.Activities.State();

this.OrderProcessingState.ID = "OrderProcessingState";

this.OrderProcessingState.Activities.Add(this.initializeOrderProcessingState);

 

正如你在上一个状态中所做的,我们还要为InvokeMethodActivity中的MethodInvoking事件指定两个事件处理函数。

private void ProcessNewOrder(object sender, EventArgs e)

{

    itemStatus = "Processing order";

}

 

private void FinalizeOrder(object sender, EventArgs e)

{

    itemStatus = "Order processed";

}

 

构造OrderCompleted状态

一个状态机工作流有两个必需的状态,一个初始状态,一个终止状态。我们要创建的最后一个状态就是终止状态OrderCompletedState。终止状态是工作流的最后一个状态,它不能包含任何子活动。

开始构造OrderCompletedState

1. 定义1个变量

类型
名称
State
OrderCompletedState

以下代码演示了如何创建最后一个状态。

//

// OrderCompleted State

//

this.OrderCompletedState = new System.Workflow.Activities.State();

this.OrderCompletedState.ID = "OrderCompletedState";

 

完成工作流类

到这里,状态机已经全部构建好了。最后一步就是把状态加到工作流中,并设好开始和终结状态。调用工作流类的Activities集合的Add方法,把状态加到工作流中。加入的顺序无关紧要。在顺序工作流中,活动加入的顺序也并非是它执行的顺序;状态机工作流是通过事件触发和状态转移来驱动的,活动加入的顺序就更没关系了。

以下的代码演示了如何把状态加入工作流中,并将初始状态和结束状态属性分别设为各自的ID。

// Construct the workflow

this.DynamicUpdateCondition = null;

this.ID = "Workflow1";

this.Activities.Add(this.WaitingForOrderState);

this.Activities.Add(this.OrderProcessingState);

this.Activities.Add(this.OrderCompletedState);

this.InitialState = "WaitingForOrderState";

this.CompletedState = "OrderCompletedState";

创建宿主程序

示例中的宿主程序是一个WinForm程序。宿主程序中有一个可以选择订单项的列表框,一个填写项目数量的文本框。当用户点击提交按钮后,订单将被提交到工作流。工作流在处理订单的过程中会调用ItemStatusUpdate接口方法,来更新订单的状态。你应该还记得这个方法是IOrderingService接口的一个方法。这个接口将在HostOrderService类中实现。这个类会用WorkflowRuntime类的AddService方法,加入到WWF引擎中。

(译者:为了能清晰的看到程序的脉络,我只列出关键的代码)

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

 

using System.Windows.Forms;

using System.Workflow.Runtime;

using System.Workflow.Runtime.Hosting;

using System.Collections;

 

namespace Microsoft.Samples.Workflow.Quickstarts.StateMachineHost

{

    public partial class MainForm : Form

    {

        private HostOrderService myHost;

        private WorkflowRuntime workflowRuntime = null;

        ……

        public MainForm()

        {

            InitializeComponent();

            ......

            myHost = new HostOrderService();

            myHost.StatusUpdate += new HostOrderService.StatusUpdateDelegate(myHost_StatusUpdate);

            workflowRuntime = new WorkflowRuntime();

            workflowRuntime.AddService(myHost);

            workflowRuntime.StartRuntime();

        }

 

        private void myHost_StatusUpdate(object sender, ItemStatusUpdateEventArgs e)

        {

            ……

            if (cbOrderId.Items.Contains(e.OrderId) == false)

            {

               cbOrderId.Items.Add(e.OrderId);

            }

        }

 

        private void btnSubmit_Click(object sender, EventArgs e)

        {

            string item = cbItems.SelectedItem.ToString();

            int quantity = (int) udQuantity.Value;

 

            myHost.SubmitNewOrder(workflowRuntime, item, quantity);

        }

    }

 

    public class ItemStatusUpdateEventArgs : EventArgs

    {

        private string _status;

        private string _orderId;

 

        public ItemStatusUpdateEventArgs(string orderId, string status)

        {

            _status = status;

            _orderId = orderId;

        }

 

        public string OrderId

        {

            get { return _orderId; }

        }

 

        public string Status

        {

            get { return _status; }

        }

    }

 

    public class HostOrderService : StateMachineWorkflowQuickstart.IOrderingService

    {   

        public delegate void StatusUpdateDelegate( object sender, ItemStatusUpdateEventArgs e );

        public event StatusUpdateDelegate StatusUpdate;

 

        private WorkflowInstance curWorkflowInstance = null;

        private string _item;

        private int _quantity;

 

        public void SubmitNewOrder(WorkflowRuntime runtime, string item, int quantity)

        {

            _item = item;

            _quantity = quantity;

 

            // submit order to workflow and receive order id

            Type type = typeof(StateMachineWorkflowQuickstart.OrderProcessingWorkflow);

 

            curWorkflowInstance = runtime.StartWorkflow(type);

           

            // submit the order to the workflow

            NewOrder(null, new StateMachineWorkflowQuickstart.NewOrderEventArgs(curWorkflowInstance.InstanceId, item, quantity));

        }

 

        public void ItemStatusUpdate(string orderId, string newStatus)

        {

            StatusUpdate( this, new ItemStatusUpdateEventArgs( orderId, newStatus ));

        }

 

        public event EventHandler<StateMachineWorkflowQuickstart.NewOrderEventArgs> NewOrder;

 

        public void RetrieveOrderDetails(out string item, out int quantity)

        {

            item = _item;

            quantity = _quantity;

        }

    }

}

 

组织简介 | 联系我们 |   Copyright 2002 ®  UML软件工程组织 京ICP备10020922号

京公海网安备110108001071号