工作流编程循序渐进(9:使用本地服务在宿主和工作流之间通信)
工作流编程循序渐进(9:使用本地服务在宿主和工作流之间通信)
[摘要]
一、简介
二、与本地服务相关的两个重要活动-HandleExternalEventActivity和 CallExternalMethodActivity
首先,让我们看一下MSDN中有关解释。有关在工作流中使用 Web 服务的实例,将在后面文章中陆续给出。 |

来自MSDN: |
[1]HandleExternalEventActivity 活动与 CallExternalMethodActivity 活动结合使用,可输入或输出与本地服务的通信。 可以直接对一般通信使用这些活动。 或者,可以创建 HandleExternalEventActivity 和 CallExternalMethodActivity 类的子类,以创建严格绑定到某个接口上的特定事件和方法的活动,并具有 ExternalDataExchangeAttribute 属性。 HandleExternalEventActivity 基类阻止工作流,直到通过 WorkflowRuntime 注册的相应本地服务引发由 InterfaceType 和 EventName 属性指定的事件。 引发该事件后,或者如果该事件在活动开始执行前引发,则将传入数据分配给在 ParameterBindings 集合中定义的绑定位置。 [2]CallExternalMethodActivity 活动和 HandleExternalEventActivity 活动可用于与本地服务进行输入和输出通信。 您可以直接使用这些活动进行一般通信,也可以创建 CallExternalMethodActivity 和 HandleExternalEventActivity类的子类以创建一些活动,这些活动严格绑定到具有 ExternalDataExchangeAttribute属性的接口上的特定事件和方法。 CallExternalMethodActivity 基类调用由向 WorkflowRuntime 注册的相应本地服务的 InterfaceType 和 MethodName 属性指定的方法。 此调用是使用从绑定位置的 ParameterBindings 集合中收集的参数以同步方式执行的。 如果该方法具有返回值,则会在活动执行完毕前将这些值设置为绑定位置。 |
三、局部步骤归纳
接口定义举例(来自MSDN): |
[ExternalDataExchange] public interface ICommunicationService { void HelloHost(string message); event EventHandler<ExternalDataEventArgs> HelloWorkflow; } |
自定义本地服务类举例(来自MSDN): |
public class CommunicationService : ICommunicationService { public event EventHandler<ExternalDataEventArgs> HelloWorkflow; public void HelloHost(string message) { Console.WriteLine("This is the message: {0}", message); //引发HelloWorkflow事件 HelloWorkflow(null, new ExternalDataEventArgs(WorkflowEnvironment.WorkflowInstanceId)); } } |
在启动工作流之前需要完成的任务示例: |
ExternalDataExchangeService externalService = new ExternalDataExchangeService(); workflowRuntime.AddService(externalService); externalService.AddService(new CommunicationService()); |
注意:因为每个服务只能具有单个实例,因而有可能有多个工作流实例同时调用服务中的方法和事件。因此在设计时需要考虑线程安全的数据访问问题。 |
四、案例分析
(一)创建控制台顺序工作流示例框架
1. 启动VS2008,单击菜单”文件“|”新建“|”项目“,选择“Sequential Workflow Console Application”模板创建一个名字为LocalServiceDemo的控制台状态机工作流示例程序。
2.之后,系统自动打开工作流设计器界面。
3. 从工具箱中拖动几个活动到工作流设计器中,得到如图所示的情形。
(二)创建自定义事件参数类
创建自定义事件参数类(用于在宿主与工作流间传递参数之用): |
class CustomServiceEventArgs:ExternalDataEventArgs { private string name; //这个公共属性用于在宿主与工作流间传递参数之用,可以是复杂的类,也可以是简单的字符串 public string Name { get { return this.name; } } public CustomServiceEventArgs(Guid instanceID, string name) : base(instanceID) { this.name = name; } } |
(三)定义本地服务接口
本地服务接口定义: |
[ExternalDataExchange] internal interface ICustService { event EventHandler<CustomServiceEventArgs> Approved; event EventHandler<CustomServiceEventArgs> Rejected; void CreateBallot(string name);//产生一次新的投票 } |
(四)定义本地服务类
定义本地服务类: |
internal class CustServiceImpl : ICustService { #region ICustService 成员 public event EventHandler<CustomServiceEventArgs> Approved; public event EventHandler<CustomServiceEventArgs> Rejected; public void CreateBallot(string name) { Console.WriteLine("现在为{0}投票。", name); ShowDlg(new CustomServiceEventArgs(WorkflowEnvironment.WorkflowInstanceId, name)); } #endregion public void ShowDlg(CustomServiceEventArgs args) { DialogResult result; string name = args.Name; result = MessageBox.Show(string.Format("是否同意,{0}", name), string.Format("当前为{0}投票", name), MessageBoxButtons.YesNo); if (DialogResult.Yes == result) { EventHandler<CustomServiceEventArgs> approved = this.Approved; if (approved != null) approved(null, args); } else { EventHandler<CustomServiceEventArgs> rejected = this.Rejected; if (rejected != null) rejected(null, args); } } } |
(五)工作流编程
///定义了一个公共根属性,以便于接收从宿主传入的投票人信息。 //定义一个表示投票人姓名信息的属性 private string votername; public string VoterName { set { this.votername = value; } get { return this.votername; } } |
(六)控制台宿主编程
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Workflow.Runtime; using System.Workflow.Runtime.Hosting; using System.Workflow.Activities;//ExternalDataExehangeService namespace LocalServiceDemo { class Program { static void Main(string[] args) { using(WorkflowRuntime workflowRuntime = new WorkflowRuntime()) { //加载本地服务 ExternalDataExchangeService dataService = new ExternalDataExchangeService(); workflowRuntime.AddService(dataService); //将自定义的本地通信服务加载到本地服务中 CustServiceImpl ls = new CustServiceImpl(); dataService.AddService(ls); AutoResetEvent waitHandle = new AutoResetEvent(false); workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { waitHandle.Set(); }; workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e) { Console.WriteLine(e.Exception.Message); waitHandle.Set(); }; //向工作流实例传递参数,注意格式 Dictionary<string, object> paras = new Dictionary<string, object>(); paras.Add("VoterName", "爱因斯坦"); WorkflowInstance instance = workflowRuntime.CreateWorkflow( typeof(LocalServiceDemo.Workflow1),paras ); instance.Start(); waitHandle.WaitOne(); Console.Read(); } } } } |
(七)观察运行结果
五、部分参考资料
相关文章:

使用Properties连接数据库
使用Properties连接数据库 要注意的是: 1.通过配置文件来连接数据库时,连接信息要以 mysql.XXX开头,否则会提示异常。 java.sql.SQLException: Access denied for user localhost (using password: YES)生成配置文件的实现代码 1、创建写入配置信息工…
两边横线,中间标题
<!DOCTYPE html> <html> <head> <title>两边横线,中间标题</title> <meta http-equiv"Content-Type" content"text/html; charsetutf-8" /> <style type"text/css"> <!--ul { mar…

交换机基础配置
请同学们下载附件中的实验并完成。转载于:https://blog.51cto.com/coffee0546/204093

python高级-模块(14)
一、python中的模块 有过C语言编程经验的朋友都知道在C语言中如果要引用sqrt函数,必须用语句#include <math.h>引入math.h这个头文件,否则是无法正常进行调用的。 那么在Python中,如果要引用一些其他的函数,该怎么处理呢&am…

RabbitMQ学习系列二:.net 环境下 C#代码使用 RabbitMQ 消息队列
上一篇已经讲了Rabbitmq如何在Windows平台安装,不懂请移步:RabbitMQ学习系列一:windows下安装RabbitMQ服务 一、理论: .net环境下,C#代码调用RabbitMQ消息队列,本文用easynetq开源的.net Rabbitmq api来实…

一步步学会使用ASP.NET 4 WEB应用程序中使用URL Routing(翻译)
创建路由 路由就是将URL路径映射到具体的物理文件。若要将路由添加到网站中,请使用 RouteCollection.MapPageRoute 方法将它们添加到RouteTable类的静态Routes属性。 将用于添加路由的方法添加到 Global.asax 文件中 如果网站还没有 Global.asax 文件,…

Properties持久的属性集
Properties 属性集合继承了Hashtable 属性包括属性名和属性值(键值对keyvalue) 作用 可以存储多个键值,与map相似可以把键值对存储到文件中可以把文件中的键值对读取到Properties对象中 构造方法: Properties() 创建一个无默认…

让你二十年后仍是人才
1.不管坐什么位置,都要保持学习的习惯出社会工作十年到十五年左右,会有一种「上下卡住」的闭塞感与无力感。因为,这个阶段的上班族虽然拥有一定的资历与经验,工作也得心应手,但上面有比自己更资深的前辈压着࿰…

Django ORM操作
Django ORM操作 一般操作 看专业的官网文档,做专业的程序员! 必知必会13条 <1> all(): 查询所有结果<2> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选…

ChineseCalendar类[转]
///<summary>///Title: ChineseCalendar类 ///Description: 中文日期工具类 ///author 万灵杰[作者] ///version 1.0.0.0 ///date 2009年7月30日 ///modify ///date ///</summary>publicclassChineseCalendar { privatestaticrea…

程序员的自我救赎---13.1:职场招聘与面试心得
《前言》 《目录》 (一) Winner2.0 框架基础分析 (二)PLSQL报表系统 (三)SSO单点登录 (四) 短信中心 (五)钱包系统 (六)GPU支付中心 &…

网络编程 UDP通信的过程 TCP通信过程 多线程文件上传
网络概述 协议 在网络之间传出数据时需要按照指定的标准来传输,标准中规定了数据的格式、大小、传输的方式、传输速率。形成统一规范—>按照规范开发的代码—>协议(应用层、传输层、网络层、链路层) InetAddress类 用来分装网络地址…

set debug mode for flex builder
1. 要具备debug功能,我们必须要首先安装Flash Player Debug 版本。windows版本2. 安装好debug版本后,我们还需要添加日志的配置文件mm.cfg。该配置文件存放的目录如下:Macintosh OS X MacH D:Library:Application Support:macromedia:mm.cfgM…

XML 解析XML文档 XML约束
XML 什么是XML Extensible Markup Language(可扩展的标记语言)他是一个语言,有自己的语法,和Java以及其他的编程无关“标记” 在文件中包含类似于张三 ,这种用尖括号括起来的叫标记,使用来标记数据的。标…

Host Only、NAT和Bridge三种网络连接
Host Only、NAT和Bridge三种网络连接 在安装好了Linux镜像之后,如何连接物理机和虚拟机呢?这就需要网络连接,网络连接有三种:HostOnly、NAT、Bridge,它们都可用于Guest虚拟机和Host物理机之间的网络通信。 一、三者的不…

OSPF 提升 一 ----基础
ospf ccnp内容 一 link-state protocols IGP 开放式的最短路径优先协议 公有协议支持中到大型的网络 spf算法 链路状态协议1.传送的LSA link status advertisement 链路状态通告 包换拓扑信息具体包括:网段的前缀 掩码 连接的路由器的…

C#实现网页截图功能
//需要添加System.Drawing及System.Windows.Forms引用 using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Windows.Forms; namespace 网页截图 { class Program { [S…

微软发布全新多核心操作系统原型:Barrelfish
Windows 7完成之后,很多人开始把目光投向微软的下一代服务器和客户端操作系统Windows 8,不过今天微软放出了一套全新操作系统的原型,开发代号“Barrelfish”。该系统由微软剑桥研究院和苏黎世理工学院联合全新开发,专为现在和未来…

Docker应用:Kubernetes(容器集群)
Docker应用:Kubernetes(容器集群) 原文:Docker应用:Kubernetes(容器集群)阅读目录: Docker应用:Hello WorldDocker应用:Docker-compose(容器编排)…
通道应用——抠头发
通道应用——抠头发 原图: 效果图: 步骤:1、打开原图的“通道面板”,选择颜色对比分明的绿色通道,并新建一个绿色通道副本;2、选择“图像”-“调整”-“色阶”,调节色阶使得头发颜色更分明些&am…

2017 ACM/ICPC 南宁赛区小结 By JSB @ Reconquista
Statistics TYPE: Onsite ContestNAME: 2017 - ICPC - Asia NanningPLAT: pc^2TIME: 2017/11/26 09:00-14:00LOCA: Guangxi UniversityTEAM: Reconquista[shb,lsmll,jsb]RANK: 8/227 3.52%SOLVE: 8/13PENALTY: 451 ◦ A - 1 ◦ E - 123 (2) ◦ F - 8 ◦ H - 55 ◦ I - 97 (1) ◦…

用户管理系统控制台版连接数据库
建User表 CREATE TABLE user (id INT(11) NOT NULL AUTO_INCREMENT,name VARCHAR(20) DEFAULT NULL,pwd VARCHAR(20) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEINNODB AUTO_INCREMENT5 DEFAULT CHARSETutf8User对象(javaBean) public class User {priva…

微信小程序组件 日历
js文件 use strict;let choose_year null,choose_month null;const conf {data: {hasEmptyGrid: false,showPicker: false},onLoad() {const date new Date();const cur_year date.getFullYear();const cur_month date.getMonth() 1;const weeks_ch [ 日, 一, 二, 三, …

node编写定时任务,for循环只执行一遍的解决办法
在用node编写定时任务时候,发现for循环只执行i0这一次,就不接着循环执行了,下面贴上代码: exports.task async function(ctx){ let { app } ctx, resultArr1 [],//查询的数据库数据 resultArr2 [];//查询的数据库…

oledb读不到dbf文件内容
最近在处理一批VFP的数据库,使用OleDB方式读取一直很正常,前两天突然碰到一张表怎么也读不出数据来,害我瞎忙了一整天,在研究了DBF文件结构后发现记录前的0x20位置存储的是0x2A。 一查才知道是删除标记,我倒࿰…

好用的截图工具
好用的截图工具...简单好用而且不大转载于:https://blog.51cto.com/dd123/208983
“AS3.0高级动画编程”学习:第二章转向行为(上)
因为这一章的内容基本上都是涉及向量的,先来一个2D向量类:Vector2D.as (再次强烈建议不熟悉向量运算的童鞋,先回去恶补一下高等数学-07章空间解释几何与向量代数.pdf) package {import flash.display.Graphics;public class Vector2D {privat…

用Azure VM + Azure Database for MySQL搭建Web服务
仍然是一篇动手实验,实验演示如何在Azure的虚拟机内部署一个Web服务器,并且使用Azure Mysql PaaS作为本应用的数据库。此实验的目的一方面是为了演示Azure IaaS层和PaaS服务配合使用的常规操作,另一方面是为之后的文章打基础,后续…

C3P0_and_pro.properties配置文档代码
C3P0-config.xml配置文件 <c3p0-config> <!-- 默认配置,如果没有指定则使用这个配置 --> <default-config><property name"driverClass">com.mysql.jdbc.Driver</property><property name"jdbcUrl">jdbc:…
电视信号——行场同步
电视信号分NTSC制和PAL制两种制式, NTSC制每秒刷新60次, 而PAL制每秒刷新50次。 水平消隐:电子枪从左到右画出象素,它每次只能画一条扫描线,画下一条之前要先回到左边并做好画下一条扫描线的准备,这之间有一段时间叫做水平消隐&am…