当前位置: 首页 > news >正文

WF与WebService

WF与WebService交互

WF中提供了WebServiceInputActivity,WebServiceOutputActivity,InvokeWebServiceActivity,WebServiceFaultActivity四个活动来完成与Webservice
的交互,下面简要介绍下这四个活动:

1.WebServiceInputActivity活动:使工作流能够从 Web 服务接收数据。 在启动 Web 服务时将自身作为 Web 服务方法发布,然后在随后调用 Web 服务
方法时接收数据。
2.WebServiceOutputActivity活动:用于响应对工作流所做的 Web 服务请求,该活动必须与WebServiceInputActivity 活动关联。
3.WebServiceFaultActivity活动:为所出现的 Web 服务错误建立模型。
4.InvokeWebServiceActivity活动:通过代理类调用 Web 服务,并传递和接收指定的参数。

应用举例

1.下面我们举例说明,由于WebServiceInputActivity活动所接收的方法必须定义在接口中,所以我们先建立一个接口IAddService ,代码如下:

namespace CaryWFLib
{
    interface IAddService
    {
        double Add(double number1, double number2);
    }
}

2.工作流设计器如下图:

wfws1

3.在工作流设计器中我们首先拖入了一个WebServiceInputActivity活动,设置其InterfaceType属性,然后MethodName,然后将IsActivating设为true,
默认为false,当选了MethodName属性后属性窗口会自动多出参数的属性。在CodeActivity活动中完成加法运算逻辑,最后是WebServiceOutputActivity
活动,工作流的代码如下:

public sealed partial class AddWorkflow: SequentialWorkflowActivity
{
     public double number1;
     public double number2;
     public double result;

     public AddWorkflow()
     {
        InitializeComponent();
     }
     private void codeActivity1_ExecuteCode(object sender, EventArgs e)
     {
         result = number1 + number2;
     }        
}
4.这个时候你就可以用项目的右键菜单里的"作为Web服务发布"来将工作流发布为WebService,发布完成后会在当前的解决方案里多出一个WebService
的项目,我们就可以运行测试了,如下图:
 
只有工作流库才可以发布为WebService,新生成的WebService项目会包含一个CaryWFLib.AddWorkflow_WebService.asmx文件和一个Web.config
配置文件,web.config文件的内容如下:
<?xml version="1.0"?>
<configuration>
  <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="CaryWFLib">
    <CommonParameters>
      <add name="ConnectionString"
           value="Initial Catalog=WorkflowPersistence;Data Source=localhost\SQLEXPRESS;Integrated Security=SSPI;" />
    </CommonParameters>
    <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.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
UnloadOnIdle="true"/> </Services> </WorkflowRuntime> <appSettings/> <connectionStrings/> <system.web> <compilation debug="false"/> <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> web.config中的SqlWorkflowPersistenceService是我们手动添加的,其他的都是自动生成的。
5.我们第一次调用WebService是正常的,如果你再次调用就会出现下错误:
System.InvalidOperationException: 在状态持久性存储中找不到 ID 为“21cf8af3-885d-47dd-acbc-530eeba794ed”的工作流。
这是由于在web.config中使用了WorkflowWebHostingModule,我们第二次调用的时候WebService会去装载之前的工作流实例,而第一次调用完成后该实
例就销毁了,如果你关掉浏览器在打开就又正常了,这是因为新的工作流实例又产生了。
 
WorkflowWebHostingModule

1.WorkflowWebHostingModule类是默认的路由机制,用于通过使用ASP.NET cookie将web服务请求路由到相应的工作流,发出这些请求的客户端要支持
cookie。这个主要目的是为了可以多次的调用一个工作流实例的方法。我们从新设计一个工作流用于解决上面的问题,将原接口扩展一下,代码如下:

namespace CaryWFLib
{
    interface IAddStatefulService
    {
        void StartWorkflow();
        double Add(double number1, double number2);
        void StopWorkflow();
    }
}

2.工作流设计如下:

wfws3

我们使用ListenActivity来监听,WebServiceInputActivity1绑定StartWorkflow方法,WebServiceInputActivity2绑定Add方法,WebServiceInputActivity3
绑定StopWorkflow方法,如果调用StopWorkflow方法,我们就在WebServiceInputActivity3的调用完成的事件中将While的条件设为false。我们在web.config
中装载了持久化服务,所以在工作流Idle的时候就进行持久化的存储,当第二次调用的时候会根据cookie中保存的工作流实例id从持久化数据库中装载相同的
工作流实例。

3.如果在其他程序中,比如winform中,我们需要手动装载持久化中的工作流实例,那我们如何知道工作流实例的id呢,我们reflector一下WorkflowWebHostingModule的代码如下:

public sealed class WorkflowWebHostingModule : IHttpModule
{
    // Fields
    private HttpApplication currentApplication;

    // Methods
    public WorkflowWebHostingModule()
    {
        WorkflowTrace.Host.TraceEvent(8, 0, "Workflow Web Hosting Module Created");
    }

    private void OnAcquireRequestState(object sender, EventArgs e)
    {
        WorkflowTrace.Host.TraceEvent(8, 0, "WebHost Module Routing Begin");
        HttpCookie cookie = HttpContext.Current.Request.Cookies.Get("WF_WorkflowInstanceId");
        if (cookie != null)
        {
            HttpContext.Current.Items.Add("__WorkflowInstanceId__", new Guid(cookie.Value));
        }
    }

    private void OnReleaseRequestState(object sender, EventArgs e)
    {
        if (HttpContext.Current.Request.Cookies.Get("WF_WorkflowInstanceId") == null)
        {
            HttpCookie cookie = new HttpCookie("WF_WorkflowInstanceId");
            object obj2 = HttpContext.Current.Items["__WorkflowInstanceId__"];
            if (obj2 != null)
            {
                cookie.Value = obj2.ToString();
                HttpContext.Current.Response.Cookies.Add(cookie);
            }
        }
    }

    void IHttpModule.Dispose()
    {
    }

    void IHttpModule.Init(HttpApplication application)
    {
        WorkflowTrace.Host.TraceEvent(8, 0, "Workflow Web Hosting Module Initialized");
        this.currentApplication = application;
        application.ReleaseRequestState += new EventHandler(this.OnReleaseRequestState);
        application.AcquireRequestState += new EventHandler(this.OnAcquireRequestState);
    }
}
4.从reflector出的源代码我们可以发现,工作流实例的id存储在名称为WF_WorkflowInstanceId的cookie中,Item为__WorkflowInstanceId__。
我们通过如下代码就可以得到工作流实例的id了,如下:
localhost.AddWorkflow_WebService ws = new localhost.AddWorkflow_WebService();
ws.CookieContainer = new System.Net.CookieContainer();
ws.Url = "http://localhost:6411/CaryWFLib_WebService1/CaryWFLib.AddWorkflow_WebService.asmx";
ws.Add(1, 2);
Uri uri = new Uri(ws.Url);
CookieCollection cc = ws.CookieContainer.GetCookies(uri);
foreach (Cookie c in cc)
{
   if (c.Name == "WF_WorkflowInstanceId")
   {
       this.Label3.Text = c.Value;
   }
}
5.由于WorkflowWebHostingModule必须要求客户端启用cookie,当不能在客户端中启用 Cookie 时我们可以从新写一个WorkflowWebHostingModule。
6.上面的发布WebService是使用WF本身提供功能,我们完全可以自己来实现,代码如下:
namespace CaryWFLib
{
    [WebService(Namespace = "http://CaryWFLibWebService.com/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class CaryWFLibWebService:System.Web.Services.WebService
    {
        private static WorkflowRuntime workflowRuntime = new WorkflowRuntime();

        [WebMethod]
        public double Add(double number1,double number2)
        {
            double result=0;
            AutoResetEvent waitHandle = new AutoResetEvent(false);
            workflowRuntime.WorkflowCompleted +=
               delegate(object sender, WorkflowCompletedEventArgs e)
               {
                   result =Convert.ToDouble( e.OutputParameters["result"]);
                   waitHandle.Set();
               };

            workflowRuntime.WorkflowTerminated +=
               delegate(object sender, WorkflowTerminatedEventArgs e)
               {
                   waitHandle.Set();
               };           
            Dictionary<string, object> wfParas = new Dictionary<string, object>();
            wfParas.Add("number1", number1);
            wfParas.Add("number2", number2);
            WorkflowInstance instance =
               workflowRuntime.CreateWorkflow(typeof(ManualAddWorkflow),wfParas);
            instance.Start();
            waitHandle.WaitOne();
            return result;
        }    
    }
}

当然这个时候,ManualAddWorkflow工作流的设计就只需要一个CodeActivity来完成加法的逻辑就可以了,WebServiceInputActivity等这些活动就不需要了。


本文转自生鱼片博客园博客,原文链接:http://www.cnblogs.com/carysun/archive/2008/12/14/WF-WebService.html,如需转载请自行联系原作者

相关文章:

  • 为何占有一个人,让你更寂寞?
  • The Chip : How Two Americans Invented the Microchip and Launched a Revolution
  • NeHe OpenGL第二十二课:凹凸映射
  • 一个技术不成熟的家伙安装office的 悲哀
  • Mysql查询优化从入门到跑路(一)数据库与关系代数
  • NeHe OpenGL第三十课:碰撞检测
  • 【调试】如何使用javascript的debugger命令进行调试(重要)
  • Struts 功能扩展 之 RequestProcessor
  • 构建ASP.NET MVC5+EF6+EasyUI 1.4.3+Unity4.x注入的后台管理系统(66)-MVC WebApi 用户验证 (2)...
  • 第一章 MySql的安装 1.1
  • Android零基础入门第61节:滚动视图ScrollView
  • 我的宽带路
  • ArrayBlockingQueue与LinkedBlockingQueue
  • 一些鲜为人知的编程事实之感想
  • GreenDao3.0新特性解析(配置、注解、加密)
  • [NodeJS] 关于Buffer
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • conda常用的命令
  • CSS实用技巧
  • css系列之关于字体的事
  • Elasticsearch 参考指南(升级前重新索引)
  • java8-模拟hadoop
  • Mysql数据库的条件查询语句
  • Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比...
  • vue--为什么data属性必须是一个函数
  • Vultr 教程目录
  • 表单中readonly的input等标签,禁止光标进入(focus)的几种方式
  • 程序员该如何有效的找工作?
  • 给第三方使用接口的 URL 签名实现
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 教程:使用iPhone相机和openCV来完成3D重建(第一部分) ...
  • ​MySQL主从复制一致性检测
  • #162 (Div. 2)
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (Matalb时序预测)PSO-BP粒子群算法优化BP神经网络的多维时序回归预测
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (分布式缓存)Redis哨兵
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (三分钟了解debug)SLAM研究方向-Debug总结
  • (收藏)Git和Repo扫盲——如何取得Android源代码
  • (顺序)容器的好伴侣 --- 容器适配器
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • (状压dp)uva 10817 Headmaster's Headache
  • .NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库
  • .NET Core 通过 Ef Core 操作 Mysql
  • .NET Core 网络数据采集 -- 使用AngleSharp做html解析
  • .net core 源码_ASP.NET Core之Identity源码学习
  • .net6Api后台+uniapp导出Excel
  • .net解析传过来的xml_DOM4J解析XML文件
  • ::什么意思
  • @converter 只能用mysql吗_python-MySQLConverter对象没有mysql-connector属性’...
  • [ IO.File ] FileSystemWatcher
  • [@Controller]4 详解@ModelAttribute
  • []串口通信 零星笔记
  • [1] 平面(Plane)图形的生成算法