关于工作流(Workflow Foundation)的一些总结归纳

本文深入探讨工作流(Workflow Foundation)的使用方法,包括如何通过可视化界面分离流程设计与程序逻辑,以及如何利用该框架处理业务逻辑和数据管理。详细介绍了工作流组件的构成、服务实现以及客户端界面的构建过程,同时提供了完整的架构示例。
其实,以我的体会,工作流(Workflow Foundation)从它一诞生就褒贬不一。至少它确实目前看起来还是比较难用。在.NET 3.5以及之前的版本中,为了实现工作流,我们还是需要编写相当多的代码。

 

我觉得,WF给我们带来的主要有几点是值得了解的

1. 通过可视化的界面将流程设计与程序逻辑分离开来。

流程设计的可以只管流程,他们不要知道怎么做。流程设计的人员可能(或者一定)不会用Visual Studio,他们可以使用一些简单的设计器工具。例如下面的这个小例子就是一个独立的程序,上面包装了WF的设计器。结合自定义Activity的设计,可以将业务逻辑隐藏起来。

image

image

 

2.业务逻辑的数据还是需要我们自己设计数据库保存以及维护的

这是很多人疑惑的,他们觉得既然有Workflow Foundation,就万事大吉了。因为工作流实例确实也有数据,而且我们可以持久化将其保存起来嘛。

停!这不是一个正确的想法。工作流的持久化服务顾名思义,其实主要是为了给我们维护长时间工作的流程信息的(可以在空闲的时候卸载,保存到数据库等)。

大家应该这样理解,Workflow Foundation只是管流程的部分,它不管数据。

没错,它只管流程。这有什么问题么,它管好这个就够了,而且确实能帮很大的忙,不是吗?

这样,我们就可以将注意力放在业务数据的管理,而不是流程状态的管理之类。

 

3. 一般一套工作流的解决方案需要包含哪些组件

image

请注意上面选中的项目,我来解释一下

3.1 WorkflowLibrary 这个项目包含了工作流设计,它是可视化设计的成果。下图是一个典型的审批流程

image

3.2 OrderApprovalEventType 这个项目包含了工作流设计时可能会用到的一些接口和事件定义。为什么需要用事件呢?一般我们的流程如果需要等待用户干预,诸如审批之类的情况,就需要这样做,因为它可能不是立即发生的。

image

注意,接口要标记为ExternalDataExchange,事件参数需要继承ExternalDataEventArgs,而且必须可序列化

 

3.3 Contracts 这个项目是标准的WCF合约定义,因为我们是分了服务器和客户端的,他们之间通过WCF通讯,包括创建流程,以及激发事件等等

image

3.4 Services,这就是具体实现的WCF服务,在这里可以启动工作流运行时,并且按照客户端指令做相应的事情。这里的代码是相当多的。

image

using System;
using System.Collections.Generic;
using System.Linq;
using Contracts;

using System.ServiceModel;
using System.Workflow.Runtime;

using OrderApprovalEventType;
using System.Workflow.Activities;

using System.Workflow.Runtime.Hosting;
using System.Workflow.Runtime.Tracking;


namespace Services
{
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]//只有一个实例
    public class OrderService:IOrderService
    {
        //运行时
        private WorkflowRuntime runtime = null;

        //所有实例
        private List
 
   instances = 
  new List
  
   ();
        
   //本地服务
        LocalService local = 
   null;

        
   public OrderService() {
            runtime = 
   new WorkflowRuntime();

            
   //添加数据交换服务,可以激发事件
            ExternalDataExchangeService svr = 
   new ExternalDataExchangeService();
            runtime.AddService(svr);

            local = 
   new LocalService();
            svr.AddService(local);

            
   //添加持久化服务,保存实例
            
   //F:/Windows/Microsoft.NET/Framework/v3.0/Windows Workflow Foundation/SQL/zh-CHS这里会有脚本
            var db = 
   "server=(local);database=WorkflowFoundation;integrated security=true";
            SqlWorkflowPersistenceService sqlsvc = 
   new SqlWorkflowPersistenceService(db);
            runtime.AddService(sqlsvc);


            
   //添加跟踪服务,可以对服务进行诊断和调试
            SqlTrackingService tracksvc = 
   new SqlTrackingService(db);
            runtime.AddService(tracksvc);
            
            

            
   //绑定有关的事件
            runtime.WorkflowStarted += 
   new EventHandler
   
    (runtime_WorkflowStarted);
            runtime.WorkflowCompleted += 
    new EventHandler
    
     (runtime_WorkflowCompleted);
            runtime.WorkflowCreated += 
     new EventHandler
     
      (runtime_WorkflowCreated);
            runtime.WorkflowAborted += 
      new EventHandler
      
       (runtime_WorkflowAborted); runtime.WorkflowTerminated += 
       new EventHandler
       
        (runtime_WorkflowTerminated); runtime.WorkflowUnloaded += 
        new EventHandler
        
         (runtime_WorkflowUnloaded); runtime.StartRuntime();
         //启动运行时 Console.WriteLine(
         "工作流服务器已经准备就绪"); 
         //加载那些保存好的流程实例 
         foreach (var item 
         in sqlsvc.GetAllWorkflows()) { var instance =(WorkflowLibrary.Workflow1)runtime.GetWorkflow(item.WorkflowInstanceId).GetWorkflowDefinition(); instances.Add( 
         new WorkflowIntanceData() { Id = item.WorkflowInstanceId, Amount = instance.Amount }); } } 
         void runtime_WorkflowUnloaded(
         object sender, WorkflowEventArgs e) { Console.WriteLine(
         "时间:{0},卸载流程:{1}", DateTime.Now, e.WorkflowInstance.InstanceId); } 
         void runtime_WorkflowTerminated(
         object sender, WorkflowTerminatedEventArgs e) { Console.WriteLine(
         "时间:{0},终止流程:{1}", DateTime.Now, e.WorkflowInstance.InstanceId); } 
         void runtime_WorkflowAborted(
         object sender, WorkflowEventArgs e) { Console.WriteLine(
         "时间:{0},中断流程:{1}", DateTime.Now, e.WorkflowInstance.InstanceId); } 
         void runtime_WorkflowCreated(
         object sender, WorkflowEventArgs e) { Console.WriteLine(
         "时间:{0},创建流程:{1}", DateTime.Now, e.WorkflowInstance.InstanceId); } 
         void runtime_WorkflowCompleted(
         object sender, WorkflowCompletedEventArgs e) { var found = instances.FirstOrDefault(d => d.Id == e.WorkflowInstance.InstanceId); 
         if (found != 
         null) instances.Remove(found); Console.WriteLine(
         "时间:{0},完成流程:{1}", DateTime.Now, e.WorkflowInstance.InstanceId); } 
         void runtime_WorkflowStarted(
         object sender, WorkflowEventArgs e) { Console.WriteLine(
         "时间:{0},启动流程:{1}", DateTime.Now, e.WorkflowInstance.InstanceId); } 
         #region IOrderService 成员 
         public 
         void StartRequest(Guid id, 
         int amount) { 
         //准备数据 var initParam =
         new Dictionary<
         string,
         object>(); initParam.Add(
         "Amount",amount); 
         //创建实例 var instance = runtime.CreateWorkflow( 
         typeof(WorkflowLibrary.Workflow1), initParam, id); 
         //保存有关数据 instances.Add( 
         new WorkflowIntanceData(){ Id = id, Amount = amount, RequestEmployee=
         "陈希章" }); 
         //启动实例 instance.Start(); } 
         public 
         void ProcessRequest(Guid id, OrderApprovalEventType.ProcessResult result, 
         string notes) { var args = 
         new ProcessEventArgs(id); args.Result = result; args.Notes = notes; 
         //从集合中删除掉有关的实例 var found = instances.FirstOrDefault(d => d.Id == id); 
         if (found != 
         null) instances.Remove(found); local.RaiseEvent(args);
         //激发事件 } 
         public List
         
           GetWorkflowInstances() { 
          return instances.Where(d => d.Amount >= 2000).ToList(); } 
          #endregion 
          #region IOrderService 成员 
          public 
          void UnLoad(Guid id) { runtime.GetWorkflow(id).Unload();
          //要求开启MSDTC服务 } 
          #endregion ~OrderService() { 
          //析构的时候将所有未完成的工作流实例保存起来 
          foreach (var item 
          in runtime.GetLoadedWorkflows()) { item.Unload(); } } 
          public 
          void UnloadAllInstances() { 
          foreach (var item 
          in runtime.GetLoadedWorkflows()) { item.Unload(); } } } [Serializable]
          //这个必须标记为可序列化 
          internal 
          class LocalService : ManagerEvent { 
          #region ManagerEvent 成员 
          public 
          event EventHandler
          
            Process; 
           #endregion 
           internal 
           void RaiseEvent(ProcessEventArgs e) { 
           //这里可能要更新数据库 
           if (Process != 
           null) Process(
           this, e); } } } 
          
         
        
       
      
     
    
   
  
 

注意:这里有一个所谓本地服务的概念,是要实现第二步的那个接口,并编写有关触发事件的代码

3.5 HostService 如上都准备好之后,接下来就是通过一定的方式托管这些服务了。我们可以采用Windows Service来托管

image

3.6 SimpleClient 最后当然少不了要有客户端界面来实现一些操作。我们这里使用了Windows Forms作为界面。

image

using System;
using System.Windows.Forms;

using System.ServiceModel;
using Contracts;

namespace SimpleClient
{
    public partial class Form1 : Form
    {

        IOrderService proxy = null;


        public Form1()
        {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            ChannelFactory
 
   factory = 
  new ChannelFactory
  
   (
   new BasicHttpBinding(), 
   new EndpointAddress(
   "http://localhost:8080/OrderService"));


            proxy = factory.CreateChannel();
        }

        
   private 
   void btRequest_Click(
   object sender, EventArgs e)
        {
            
   int amount = 
   int.Parse(txtAmount.Text);
            proxy.StartRequest(Guid.NewGuid(), amount);
            MessageBox.Show(
   "已经发起了一个订单");
        }

        
   private 
   void btGet_Click(
   object sender, EventArgs e)
        {
            dgvRequests.DataSource = proxy.GetWorkflowInstances();

        }

        
   private 
   void dgvRequests_CellEnter(
   object sender, DataGridViewCellEventArgs e)
        {
            btOK.Enabled = btCancel.Enabled = 
   true;
        }

        
   private 
   void dgvRequests_CellLeave(
   object sender, DataGridViewCellEventArgs e)
        {
            
   //btOK.Enabled = btCancel.Enabled = false;

        }

        
   private 
   void btOK_Click(
   object sender, EventArgs e)
        {
            var row = dgvRequests.Rows[dgvRequests.SelectedCells[0].RowIndex];
            var id = (Guid)row.Cells[0].Value;


            proxy.ProcessRequest(
                id, OrderApprovalEventType.ProcessResult.Approval, txtNotes.Text);


                
        }

        
   private 
   void btCancel_Click(
   object sender, EventArgs e)
        {
            var row = dgvRequests.Rows[dgvRequests.SelectedCells[0].RowIndex];
            var id = (Guid)row.Cells[0].Value;


            proxy.ProcessRequest(
                id, OrderApprovalEventType.ProcessResult.Reject, txtNotes.Text);
        }

        
   private 
   void btUnload_Click(
   object sender, EventArgs e)
        {
            var row = dgvRequests.Rows[dgvRequests.SelectedCells[0].RowIndex];
            var id = (Guid)row.Cells[0].Value;

            proxy.UnLoad(id);
        }
    }
}

  
 

这样,一套工作流解决方案就做好了。这个架构可以供很多朋友参考

 

另外,下面有几篇有关的文章可以参考学习

工作流内部工作原理(一)

http://blogs.msdn.com/cnflow/archive/2010/04/16/9996989.aspx

工作流内部工作原理(二)

http://blogs.msdn.com/cnflow/archive/2010/04/16/9996992.aspx

工作流内部工作原理(三)

http://blogs.msdn.com/cnflow/archive/2010/04/16/9996995.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值