WF 和Web Service 的关联主要是两种场景:
其一,WF可以调用一个Web Service;
其二是,你可以将一个WF 发布成一个Web Service
在WF中使用/调用Web Services 是非常容易的,如果你使用过Visual Studio开发Web Service和调用过Web Service,那么在WF中调用一个Web Service也几乎是相同的。基本上是通过.NET Framework 的SoapHttpClientProcotol 类的功能来调用Web Services
简单的说就是先获得WSDL,然后根据WSDL产生一个从SoapHttpClientProcotol 派生的类,之后可以使用SoapHttpClientProcotol.Invoke 调用Web Service
而将一个WF Workflow 发布成一个Web Services,这种功能可以将一个Workflow封装到一个WebServices中,从而使得外部的其它客户端能够通过Web Service访问和调用Activity。
无论是在WF中调用Web Service还是将一个WF 发布成一个Web Service,在WF Beta2 中,你都是通过WF提供的Activity来使用或实现这些功能。
在WF 中调用Web Service
既然是调用Web Service,那么WF Beta2 就提供了一个InvokeWebServiceActivity ,你可以将它拖入到WF设计器中。
当你拖这个Activity到设计界面时,类似于VS 2005传统的添加Web 引用的对话框会弹出来,你会在这里输入.asmx或WSDL的Web地址,如果成功WF的项目中会多一个Web References 的目录,VS会根据.asmx 或WSDL将产生SoapHttpClientProcotol 的代理类。
点击你拖入成功的InvokeWebServiceActivity ,那么你会发现下面的一些属性必须设置:
public localhost.OrderData oData = new WFWebService.localhost.OrderData();
public localhost.OrderInfo oInfo = new WFWebService.localhost.OrderInfo();
这样在WF的属性区域, ReturnValue 和orderInfo 区域你就可以进行设置了。
设置完上述3个属性后,一个WF可以正确进行编译了。设置了调用方法的输入输出参数之后,也就可以调用了。
WF提供了两个方法,一个是Invoked ,一个Invoking 。Invoking 是在InvokeWebServiceActivity 被执行之前被WF调用,Invoked 则是在InvokeWebServiceActivity 被执行之后调用。在上例中Invoked方法中你再使用oData ,这里面就是调用的结果了,当然如果调用成功的话。
所以整个的步骤非常清晰:
ASP.NET V2.0 可以使用EnableSession 属性来支持Session的情况,当你设置[WebMethod(EnableSession=true)],那么客户端每次调用Web Service的这个方法后,ASP.NET引擎都会传一个HTTP cookie 到这个客户端,服务器端可以使用HttpContext.Session 来保存客户的状态信息。
WF 也支持在一个Workflow中通过cookie 支持多个InvokeWebServiceActivity的调用在一个Session中
这时候,你需要设置InvokeWebServiceActivity的SessionId属性,如果你将一个Workflow中的多个InvokeWebServiceActivity的SessionId 设置成相同的,那么WF在调用和执行完第一个InvokeWebServiceActivity 之后,也会以相同的cookie 传回给Web Service的服务器端,以确保服务器端能够跟踪到客户端的情况。SessionId 是一个字符串,如果是空字符串,则表示会启用一个新的Session。
将一个Workflow 发布成 一个Web Service
这里你主要是使用下面三个Activity-WebServiceInputActivity ,WebServiceOutputActivity 和WebServiceFaultActivity
创建的步骤:
<?xml version="1.0"?>
<configuration xmlns=" http://schemas.microsoft.com/.NetConfiguration/v2.0">
<configSections>
<section name="WorkflowRuntime" type="System.Workflow.Runtime.Configuration.WorkflowRuntimeSection, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</configSections>
<WorkflowRuntime Name="WorkflowServiceContainer">
<Services>
<add type="System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add type="System.Workflow.Runtime.Hosting.DefaultWorkflowTransactionService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</Services>
</WorkflowRuntime>
<connectionStrings/>
<system.web>
<compilation debug="false">
<assemblies>
<add assembly="System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Drawing.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Workflow.Activities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add assembly="System.Workflow.ComponentModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add assembly="System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add assembly="Microsoft.Build.Tasks, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Messaging, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.DirectoryServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="Microsoft.Build.Utilities, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="Microsoft.Build.Framework, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
</assemblies>
</compilation>
<httpModules>
<add type="System.Workflow.Runtime.Hosting.WorkflowWebHostingModule, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" name="WorkflowHost"/>
</httpModules>
</system.web>
</configuration>
之后原来Workflow的编译结果会增加到当前Web Service项目的Bin目录中。最后还有一个原来Workflow项目名加_WebService的.asmx 文件
发布成Web Services
总来来说,发布做了下面几件事情
最终我们看得WF 对Web Service的支持情况使得你有两种非常常用的使用模式:
其一,可以非常容易和直接的让WF调用Web Service,非常容易的传递数据到Workflow 和WF进行通信,同时架构上很好地支持了SOA
其二,你可以非常容易地通过一个接口将Workflow暴露成一个Web Service,供多种客户端进行调用。
一些不足:
目前的WF Beta2的InvokeWebServiceActivity 只支持从SoapHttpClientProcotol 继承的派生类,那么调用Indigo (WCF)或 WSE产生的Web Service则有待增强和补充。另一方面除了导出成Web Service方式外,下个版本应该增加对BPEL 格式的导出和支持BPEL Activity,但显然两者的情况一样,无论WCF 还是BPEL目前都还在开发阶段,还没有到实际的产品和应用阶段。
其一,WF可以调用一个Web Service;
其二是,你可以将一个WF 发布成一个Web Service
在WF中使用/调用Web Services 是非常容易的,如果你使用过Visual Studio开发Web Service和调用过Web Service,那么在WF中调用一个Web Service也几乎是相同的。基本上是通过.NET Framework 的SoapHttpClientProcotol 类的功能来调用Web Services
简单的说就是先获得WSDL,然后根据WSDL产生一个从SoapHttpClientProcotol 派生的类,之后可以使用SoapHttpClientProcotol.Invoke 调用Web Service
而将一个WF Workflow 发布成一个Web Services,这种功能可以将一个Workflow封装到一个WebServices中,从而使得外部的其它客户端能够通过Web Service访问和调用Activity。
无论是在WF中调用Web Service还是将一个WF 发布成一个Web Service,在WF Beta2 中,你都是通过WF提供的Activity来使用或实现这些功能。
在WF 中调用Web Service
既然是调用Web Service,那么WF Beta2 就提供了一个InvokeWebServiceActivity ,你可以将它拖入到WF设计器中。
当你拖这个Activity到设计界面时,类似于VS 2005传统的添加Web 引用的对话框会弹出来,你会在这里输入.asmx或WSDL的Web地址,如果成功WF的项目中会多一个Web References 的目录,VS会根据.asmx 或WSDL将产生SoapHttpClientProcotol 的代理类。
点击你拖入成功的InvokeWebServiceActivity ,那么你会发现下面的一些属性必须设置:
- 1. Proxy Class --这个必须设置一个从SoapHttpClientProcotol 派生出来的类,一般你设置了Web References ,那么这个属性会自动设置好。但是假如你要调用一个Web Service的多个方法,那么你只用加一次Web References,后面你拖入InvokeWebServiceActivity 的时候,你会选择取消键,关闭Add Web References的对话框,而选择自己手动的给ProxyClass进行赋值,另外一种情况是你手工生成了一个从SoapHttpClientProcotol派生的Web Service代理类,那么你也可以手工的赋值。
- 2. URL-- 这个就是Web Service的URL,如果你使用Add Web References的对话框那么完成后,这个属性也自动被赋值了。如果你选择手动的方式,那么你需要将Web Service的URL赋给这个属性。比如:http://www.dotnettools.org:6407/WebService/CoolWebService.asmx
- 3. MethodName -- 这个就是你想调用Web Services的方法名了,一般这个属性赋值之后,WF 设计器会增加一个Properties 区域,因为可能这个方法是需要输入参数和有返回值的。Web Service的输入输出参数都是通过属性来传入的,所以你可以需要给这个Workflow增加一些属性。
public localhost.OrderData oData = new WFWebService.localhost.OrderData();
public localhost.OrderInfo oInfo = new WFWebService.localhost.OrderInfo();
这样在WF的属性区域, ReturnValue 和orderInfo 区域你就可以进行设置了。
设置完上述3个属性后,一个WF可以正确进行编译了。设置了调用方法的输入输出参数之后,也就可以调用了。
WF提供了两个方法,一个是Invoked ,一个Invoking 。Invoking 是在InvokeWebServiceActivity 被执行之前被WF调用,Invoked 则是在InvokeWebServiceActivity 被执行之后调用。在上例中Invoked方法中你再使用oData ,这里面就是调用的结果了,当然如果调用成功的话。
所以整个的步骤非常清晰:
- 1. 将InvokeWebServiceActivity 拖入到设计器中。
- 2. 设置MethodName 属性
- 3. 手工设置或在Invoking 方法中设置输入和输入的参数
- 4. 在Invoked 方法中填写代码获得,调用后的结果。
ASP.NET V2.0 可以使用EnableSession 属性来支持Session的情况,当你设置[WebMethod(EnableSession=true)],那么客户端每次调用Web Service的这个方法后,ASP.NET引擎都会传一个HTTP cookie 到这个客户端,服务器端可以使用HttpContext.Session 来保存客户的状态信息。
WF 也支持在一个Workflow中通过cookie 支持多个InvokeWebServiceActivity的调用在一个Session中
这时候,你需要设置InvokeWebServiceActivity的SessionId属性,如果你将一个Workflow中的多个InvokeWebServiceActivity的SessionId 设置成相同的,那么WF在调用和执行完第一个InvokeWebServiceActivity 之后,也会以相同的cookie 传回给Web Service的服务器端,以确保服务器端能够跟踪到客户端的情况。SessionId 是一个字符串,如果是空字符串,则表示会启用一个新的Session。
将一个Workflow 发布成 一个Web Service
这里你主要是使用下面三个Activity-WebServiceInputActivity ,WebServiceOutputActivity 和WebServiceFaultActivity
创建的步骤:
- 1. 你必须创建一个Activity Library 的项目,否则你的Workflow不能被发布成一个Web Service
- 2. 拖入一个WebServiceInputActivity 到设计器中,设置InterfaceType,MethodName 和输入输出的属性 属性。
- 3. 增加其它的WF Activity 实现功能或流程,也可以将逻辑转到一个WebServiceFaultActivity 上
- 4. 拖入一个WebServiceOutputActivity作为输出
- 5. 发布这个项目到一个Web Services
- 1. WebServiceInputActivity 在一个Workflow中只有一个,因为它意味着Workflow从Web Service中接收数据,在发布时刻,意味这WebServiceInputActivity将把自己发布成一个Web Service的方法。当客户端调用时,WorkflowServ启动,并开始接收数据。
- 2. InterfaceType -你必须先申明一个接口,表示Workflow想要暴露的接口和方法,其实就是Web Service的WSDL 产生的依据
- 3. MethodName,有了InterfaceType,那么你就可以将一个WebServiceInputActivity 和接口中的一个方法对应起来。设置了MethodName 之后,就会出现Properties 域,意味这个方法可能有输入参数,你需要通过Workflow的参数或属性将方法的输入产生进行设置。
- 4. 因为有了InterfaceType,同时你又将接口中的一个方法和WebServiceInputActivity 对应起来,所以你需要代码或另外的Activity实现这个方法的功能,你可以在WebServiceInputActivity的InputReceived 方法中实现功能,也可以在WebServiceInputActivity 加入其它的Activity来实现Workflow的功能。
- 5. WebServiceFaultActivity 可以产生一个SOAP的异常到客户端,但是它不会终止工作流的运行,它和 ASMX Web Service的方法抛出一个异常是一样的。WebServiceFaultActivity 只对请求-应答(request-response)方式的Web Service起作用,另外如果Workflow Web Service工作的过程中,中断工作流,那么也会抛出一个SOAP的异常。
- 6. 实现了接口的功能之后,就可以使用WebServiceOutputActivity 输出结果作为Web Service的应答了。WebServiceOutputActivity 必须和一个WebServiceInputActivity配合使用,不能单独进行使用。WebServiceOutputActivity 有一个InputActivityName属性,就是要指明OutputActivity 和哪个WebServiceInputActivity 是配对的,设置完后会出现Properties 域,一般在这里设置RuturnValue 属性。WebServiceOutputActivity 还提供了一个方法SendingOutput ,这个方法一般是在WebServiceOutputActivity 执行前被调用,你可以再这里对输出的信息再进行一些处理和操作。
- 7. 这里要特别注意WebServiceInputActivity 和WebServiceOutputActivity 必须配对使用,而且一个WebServiceInputActivity和WebServiceOutputActivity 之间不要添加第二个WebServiceInputActivity,因为第一个WebServiceInputActivity还没有返回和输出,第二个WebServiceInputActivity又在等待第一个WebServiceInputActivity 输出和返回。
- 8. 一个Activity Library 可以暴露成一个Web Service,其中的每个WebServiceInputActivity/WebServiceOutputActivity对可以暴露成一个Web Service的方法,InterfaceType 则是客户端和服务器端的和约(Contract)
- 9. 发布是相当简单的,你只用在VS2005中选择当前的项目,然后选择 发布成一个Web Service,当完成后,会增加一个新的Web Service项目。如果你原来的Workflow项目是myWebServiceWorkflowLib.OrderServiceWorkflow ,那么会产生一个myWebServiceWorkflowLib.OrderServiceWorkflow__WebService 的Web Service项目,即增加一个后缀为__WebService 的ASP.NET Web Service项目,然后会自动添加一个web.config 配置Workflow到WorkflowWebHostingModule 方式,保证在ASP.NET的情况下workflow能正常初始化。
<?xml version="1.0"?>
<configuration xmlns=" http://schemas.microsoft.com/.NetConfiguration/v2.0">
<configSections>
<section name="WorkflowRuntime" type="System.Workflow.Runtime.Configuration.WorkflowRuntimeSection, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</configSections>
<WorkflowRuntime Name="WorkflowServiceContainer">
<Services>
<add type="System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add type="System.Workflow.Runtime.Hosting.DefaultWorkflowTransactionService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</Services>
</WorkflowRuntime>
<connectionStrings/>
<system.web>
<compilation debug="false">
<assemblies>
<add assembly="System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Drawing.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Workflow.Activities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add assembly="System.Workflow.ComponentModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add assembly="System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add assembly="Microsoft.Build.Tasks, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Messaging, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.DirectoryServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="Microsoft.Build.Utilities, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="Microsoft.Build.Framework, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
</assemblies>
</compilation>
<httpModules>
<add type="System.Workflow.Runtime.Hosting.WorkflowWebHostingModule, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" name="WorkflowHost"/>
</httpModules>
</system.web>
</configuration>
之后原来Workflow的编译结果会增加到当前Web Service项目的Bin目录中。最后还有一个原来Workflow项目名加_WebService的.asmx 文件
发布成Web Services
总来来说,发布做了下面几件事情
- 1. 建立一个_WebService的Web Service 项目
- 2. 建立一个配置文件
- 3. 建立一个_WebService的.asmx 的Web Service
- 4. 将Workflow 的编译结果复制到项目的bin目录中
最终我们看得WF 对Web Service的支持情况使得你有两种非常常用的使用模式:
其一,可以非常容易和直接的让WF调用Web Service,非常容易的传递数据到Workflow 和WF进行通信,同时架构上很好地支持了SOA
其二,你可以非常容易地通过一个接口将Workflow暴露成一个Web Service,供多种客户端进行调用。
一些不足:
目前的WF Beta2的InvokeWebServiceActivity 只支持从SoapHttpClientProcotol 继承的派生类,那么调用Indigo (WCF)或 WSE产生的Web Service则有待增强和补充。另一方面除了导出成Web Service方式外,下个版本应该增加对BPEL 格式的导出和支持BPEL Activity,但显然两者的情况一样,无论WCF 还是BPEL目前都还在开发阶段,还没有到实际的产品和应用阶段。