现在的位置: 首页 > 综合 > 正文

WF工作流技术内幕 —— 通过Web服务调用Workflow工作流

2013年10月08日 ⁄ 综合 ⁄ 共 9308字 ⁄ 字号 评论关闭

在开发一个企业ERP系统时,其业务流程是开发的关键,系统往往会将开发好的业务方案发布为Web服务以供外界调用。客户可以通过服务器,互联网等等方式 去调用服务,而解决业务上需要及信息的交换问题。有见及此,微软在.NET 3.0基础上发布了WF,WCF,以及WCS,WPF(为开发表现层而设)。WF,WCF正是解决企业核心问题的关键,通过WF可以轻松地轻松地按照业务 逻辑去实现开发,然后凭借WCF的强大功能把同一服务绑定多个不同的EndPoint,这样客户端与服务与服务器端通讯就不会再受开发语言的影响。

 

 

在这章里面只是为你讲述如何将WF与Web Service结合使用,而关于WF的开发的详细介绍请参考(WF技术内幕 )。WF与Web Service相互调用分为两情况:

  1. 当客户只希望传入一些基础数据,而直接获取计算结果时,我们可以将WF发布为一个Web Service,这样就可以将WF实现的功能公开到互联网上,通过Web服务可以解决服务器与客户端之间开发语言的束缚。
  2. 当工作流的每个操作步骤都需要调用Web服务来获取结果时,我们则可以使用InvokeWebServiceWorkflow在工作流中调用Web Service来实现(具体操作可参考通过InvokeWebServiceActivity在Workflow工作流中调用Web服务 ) 。

在开发中小型ERP开发初期,往往都会把重点放在业务流程上,只要深入了解企业的业务流程后,将DAL实现为最基础的单表操作,然后就可以轻松地以 WF实现业务层的开发,最后就可以把WF作为服务公布在互联网上(当然在构建中大型系统时,会实现多层开发模式,使用工作流直接去实现业务逻辑,最后以 Web Service方式公开服务)。
而在这里,重点不是介绍ERP的开发,而只是想介绍一下如何将WF公开为Web服务,下面我们还是以“Hello World”为例子。
首先开发一个接口

        namespace Microsoft.IService
       {
            public interface IService_T1
            {
                   string DoWork();
             }

       }       

 

然后新建一个顺序工作流,分别插入WebServiceInputActivity和WebServiceOutputActivity作为启动,结束 项。WebServiceInputActivity是服务的启动标记,而WebServiceOutputActivity是服务的结束标记。

 

 

       注意,把webServiceInputActivity1的InActivating设置为True,这是证明webServiceInputActivity1为此工作流的启动项的标志。 然后InterfaceType设置为对应接口Microsoft.IService.IService_T1,将MethodName方法名设置为DoWork

 

 

 

在工作流的方法中设置codeActivity的执行方法里面设置方法内容

namespace Microsoft.Workflows

{

      public sealed partial class Workflow4 : SequentialWorkflowActivity
     {
        public string Data ;

        public Workflow4()
        {
            InitializeComponent();
        }

        private void codeActivity1_ExecuteCode(object sender, EventArgs e)
        {
            Data = "Hello World";
        }
     }

}

 

最后,在webServiceOuputActivity的InputActivityName设置为webServiceInputActivity1,表示通过webServiceOutputActivity1来结束webServiceInputActivity1,然后把ReturnValue属性设置为Data

 

 

这时候,基础的设置已经完成,现在在项目属性上选择“作为Web服务发布”。

 

 

此时,系统会自动把Workflow发布为*.asmx,生成的.asmx文件如下:

<%@ WebService Class="Microsoft.Workflows.Workflow4_WebService " %>

//此处Class名称与Workflow的空间名和类名相对应

 

再为服务添加必要的配置文件:

<?xml version="1.0"?>
<configuration>
    <configSections>
        <section name="WorkflowRuntime" type="System.Workflow.Runtime.Configuration.WorkflowRuntimeSection, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
    </configSections>
    <WorkflowRuntime Name="WorkflowServiceContainer">
        <Services>
            <add type="System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
            <add type="System.Workflow.Runtime.Hosting.DefaultWorkflowCommitWorkBatchService, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      <add type="System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" UnloadOnIdle="true" LoadIntervalSeconds="5" ConnectionString="Data Source=LESLIE-PC;Initial Catalog=WorkflowPersistence;Integrated Security=True"/>

       //这里是为Workflow添加SQL数据库持久化服务,这是可选设置。
        </Services>
    </WorkflowRuntime>
    <appSettings/>
    <connectionStrings/>
    <system.web>     
        <compilation debug="true"/>  
        <authentication mode="Windows"/>       
        <httpModules>
            <add type="System.Workflow.Runtime.Hosting.WorkflowWebHostingModule, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" name="WorkflowHost"/>
        </httpModules>
    </system.web>
</configuration>

 

 

 

这时候在网络上第一次调用服务时,系统会正常操作。

 

<? xml version="1.0" encoding="utf-8" ?>
<string xmlns="http://tempuri.org/">Hello World</string>

但第二次调用。系统将提示提示一个错误,这是因为WorkflowWebHostingModle HTTP模块是使用Cookies来存储工作流的GUID的,当工作流在服务器返回时,SQL持久化数据器里将不再储存这个GUID。这时候需要关闭浏览器,重新启动才能正常运行。
System.InvalidOperationException: 在状态持久性存储中找不到 ID 为“3a8b9688-fb3f-4a10-bb84-6bf99c30119a”的工作流。
总结,通过WF可以轻松企业的业务逻辑,再结合Web Service在互联网上发布,就可以供给不同客户端使用,从而摆脱开发语言的困扰。以上的例子只是将WF发布为Web服务的最基础用法,因为 Workflow对象只会暂时存在,当服务结束时,Workflow对象就会被清理。但是很多时候系统可能要求能维持状态并支持多个Web Service调用的工作流,下一章将为你详细介绍有关内容。

如果你曾经负责开发企业ERP系统或者OA系统,工作流对你来说一定并不陌生。工作流(Workflow)是对工作流程及其各操作步骤之间业务规则 的抽象、概括、描述。工作流要解决的主要问题是:为实现某个业务目标,在多个参与者之间,利用计算机,按某种预定规则自动传递文档、信息或者任务。有见及 此,微软在.NET 3.0基础上发布了WF,WCF,以及WCS(身份验证解决方案),WPF(为开发表现层而设)。WF正是解决企业核心问题的关键,通过WF可以轻松地轻 松地按照业务逻辑去实现开发,然后把WF发布为Web服务,这样客户端与服务与服务器端通讯就不会再受开发语言的影响,通过Web服务就可以轻松调用WF 去实现业务操作。

 

 

 

下面以一个简单的订单录入系统为例子,为你介绍一下如何将Workflow工作流发布为Web服务。

为了实现一个持久化工作流,首先以实用工具sqlcmd来建立一个本地数据库,打开命令提示符窗口,输入

sqlcom -S localhost/SQLEXPRRESS -E -Q "create database WorkflowPersistence"

然后打开文件夹

/Microsoft.Net/Framework/v3.0/Windows Workflow Foundation/SQL/[Lauguage]

里面有2个脚本文件

SqlPersistenceService_Schema.sql , SqlPersistenceService_Logic.sql

在数据库WorkflowPersistence上运行此脚本文件,数据库就可以成功创建。

 

实例描述:当客户第一次加入订单时通过Web服务调用Start方法来创建新的Workflow对象实例,之后可以多次调用AddOrder方法添加订 单,在订单没有提交前,此工作流对象实例会处于一个持久化的状态。当服务器处于空闲状态下Workflow对象的有关数据会存储于 WorkflowPersitence数据库里面,这样做可以有效减少服务器缓存的压力。最后调用End方法提交订单后,Workflow工作流对象才会 结束,Workflow对象的数据就会在数据库中被删除。

 

这里先定义一个Order类,别忘记给对象加上Serializable串行化属性

[Serializable]      

public class Order

{...}

 

为Order开发一个操作类OrderManager,里面包括一个方法AddOrder,当每加入一个Order,方法就会返回新加入Order的ID

public class OrderManager        

{  

     public int AddOrder(Order order)

     {..........}

}

 

现在对应此实例我们先开发一个接口IService_T1,Start方法表示启动此Workflow工作流,而End表示此工作流完结

namespace Microsoft.IService
{
    public interface IService_T1
    {
        void Start();
        int AddOrder(Order order);
        void End();
    }
}

 

下图是这个Workflow的完整视图,我们先使用webServiceInputActivity1来启动服务

 

 

 

在这里将webServiceInputActivity1的IsActivating属性设置为True,这意味着以此活动激活此Workflow对象实例,然后把InterfaceType设置为Microsoft.IService.IService_T1,并把MethodName设置为Start,这时候当客户端调用Start方法时,Workflow对象实例就会被激活。

 

 

然后设置WhileActivity的循环条件(this.IsRepeated==true),这说明只要IsRepeated的值为True, WhileActivity就可以持续运行,则此Workflow处于持久化状态

 

 

 

现在为listenActivity1设置2个事件驱动活动,在左边的事件驱动活动中,分别加入webServiceInputActivity2, codeActivity1, webServiceOutputActivity1。将webServiceInputActivity2的InterfaceType设置为 Microsoft.IService.IService_T1,再把MethodName设置为AddOrder,将AddOrder方法中的参数order绑定为此Workflow对象中的参数_order (参考完整代码),这样就可以通过webServiceInputActivity2调动AddOrder方法。然后在codeActivity的codeActivity_ExecuteCode方法中加入操作代码。

 

 

 

 

 

 

最后通过webServiceOutputActivity1结束操作,把InputActivityName属性设置为webServiceInputActivity2,将ReturnValue绑定变量id 。这样系统在插入Order后就可以获取AddOrder方法的返回值(int) id。

 

 

现在,可以在右边的事件驱动活动中,插入一个webServiceInputActivity3,把InterfaceType设置为Microsoft.IService.IService_T1,把MethodName设置为End,然后添加事件InputReceived的处理方法webServiceInputActivity3_InputReceived,通过此方法把IsRepeate属性设置为false,这样就可以调动此活动来终于循环,结束此工作流。

 

 

此为该Workflow的完整代码:

namespace Microsoft.Workflows

{

 public sealed partial class Workflow: SequentialWorkflowActivity
 {
        public Order _order ;
        public int id ;
        public bool IsRepeate = true ;

        public Workflow2()
        {
            InitializeComponent();
        }
        //当调用AddOrder方法时执行此操作,通过orderManager对象插入order,最后返回值orderID赋值给此Workflow参数id
        private void codeActivity1_ExecuteCode(object sender, EventArgs e)
        {
             OrderManager orderManager=new OrderManager();

             int orderID=orderManager.AddOrder(order);

             this.id=orderID;
        }
        //当调用webServiceInputActivity3活动时,把IsRepeate的值设置为false,这样可以终止循环给束此工作流对象。
        private void webServiceInputActivity3_InputReceived(object sender, EventArgs e)
        {
            IsRepeate = false;
        }
  }

}

 

这时候右键点击此“项目”,选择 “把此Workflow作为Web发布”,得到以下ASMX文件

Microsoft.Workflows.Workflow2_WebService.asmx

<%@WebService Class="Microsoft.Workflows.Workflow2_WebService" %>

 

添加配置文件

<?xml version="1.0"?>
<configuration>
    <configSections>
        <section name="WorkflowRuntime" type="System.Workflow.Runtime.Configuration.WorkflowRuntimeSection, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
    </configSections>
    <WorkflowRuntime Name="WorkflowServiceContainer">
        <Services>
            <add type="System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
            <add type="System.Workflow.Runtime.Hosting.DefaultWorkflowCommitWorkBatchService, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      <add type="System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" UnloadOnIdle="true" LoadIntervalSeconds="5" ConnectionString="Data Source=LESLIE-PC;Initial Catalog=WorkflowPersistence;Integrated Security=True"/>

       //这里是为Workflow添加SQL数据库持久化服务,因为这里要是测试持久化的工作流,此配置是必须的。
        </Services>
    </WorkflowRuntime>
    <appSettings/>
    <connectionStrings/>
    <system.web>     
        <compilation debug="true"/>  
        <authentication mode="Windows"/>       
        <httpModules>
            <add type="System.Workflow.Runtime.Hosting.WorkflowWebHostingModule, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" name="WorkflowHost"/>
        </httpModules>
    </system.web>
</configuration>

 

调用Start方法启动Workflow,然后就可以直接调用AddOrder方法,你会发现与上一篇实例不同的是,在上一篇的例子中,每个实例只允许调用一次,当页面未被重新加载时多次调用就会出现错误提示。而在这一篇的例子中,AddOrder可以多次调用,并能正常运行,这就证明了你调用的Workflow的实例对象已经一个持久化工作流,当你未调用End结束服务时,此工作流对象都可以正运行。

 

 

最后,你可以调用End方法来结束操作,当操作结束后,再调用AddOrder,系统就会出现错误显示:

System.InvalidOperationException: 在状态持久性存储中找不到 ID 为“3a8b9688-fb3f-4a10-bb84-6bf99c30119a”的工作流。

 

总结一下,通过持久化服务流的开发,可以保持工作流实例的活动状态,这样就可以通过多个Web服务进行相互调用。使用这种技术来实现基于工作流的应用程序 ,就可以将它们通过Web服务公开经客户端,并能维持工作状态。

Web服务和WF可以实现相互调用,在这两章里面,为大家介绍如何将工作流发布为Web服务,下一章将为大家介绍通过InvokeWebServiceWorkflow在WF里面调用Web服务。

抱歉!评论已关闭.