WF 从入门到精通(第二章):workflow 运行时

学习完本章后,你将掌握:

1.在你的应用程序中使用workflow

2.理解“WorkflowRuntime”对象的的基本功能

3.知道如何启动和停止workflow 运行时

4.能够使用各种workflow 运行时的相关事件

当 你在WF 环境中执行任务时,需要一些东西来监管执行的过程,这个东西就是命名为“WorkflowRuntime”的对象。 WorkflowRuntime 启动一个独立的工作流任务。在你的任务执行过程中,WorkflowRuntime 也会针对不同的情况响应对应的事件。并 且,WorkflowRuntime还能在你的执行环境中增加一个附加的服务来保持跟踪。

WF 架构纵览见下图:

image.png


WF 和你的应用程序并行执行。其实,我们需要你的应用程序作为宿主。宿主应用程序可以是Windows Forms 应用程序,控制台应用程序,ASP.NET WEB 应用程序,甚至可以是一个Windows Server。WF 运行时和你的应用程序同在一个.NET 应用程序域执行,每个应用程序域只有一个唯一的WorkflowRuntime 实例,试图在一个 应用程序域中建立第二个WorkflowRuntime 的实例的话,其结果就是抛出一个“InvalidOperationException”异常。

workflow 应用程序-“workflows”-意思指创建的逻辑上的一组活动。这些逻辑上的活动用来完成你需要的工作流任务。当你宿主workflow 运行时的时 候,其实你就在操作工作

流中的活动并让workflow 运行时执行他们。其结果就是生成一个workflow 实例,workflow实例是一个当前正执行 的workflow 任务,它能自己完成逻辑上的一组活动,回忆第一章吧,

活动能执行你提供的代码并且能对输入的数据做出相应的决定。下一章我们将简述工作 流实例,后面几章将对活动进行介绍。


在宿主应用程序中添加WF


一、创建一个名称为WorkflowHost 的控制台应用程序项目

二、为项目添加名为System.Workflow.Runtime 的引用

三、宿主workflow 运行时

1.打开Program.cs 文件准备编辑

2.在“using System.Text;”下添加以下代码:

“using System.Workflow.Runtime”

3.定位到“Main”方法,在里面添加以下代码:

WorkflowRuntime workflowRuntime=new WorkflowRuntime();

4.编译程序确认没有错误。在本章我们都将使用这一应用程序。

四、深入了解WorkflowRuntime 对象

我们现在已经在我们的宿主应用程序中建立了一个 WorkflowRuntime 类型的实例,该是简单的了解怎样和这个对象交互的时候了。和大多数有用的 对象一样,WorkflowRuntime 也暴露了一些方法和属性,我们可用他们来控制Workflow 运行时的环境。表2-1 列出了所有WorkflowRuntime 属性,表2-2 则列出了我们经常使用的方法。


表2-1 WorkflowRuntime 的属性

属性     功能

IsStarted    

    用来指明workflow 运行时是否已经启动并准备接受workflow 实例。当宿主调用“StartRuntime”前IsStarted 为False。期间它一直维持True 直到宿主调用

“StopRuntime”为止。需注意的是当它正在运行中你不能增加核心服务。

Name

    获取或设置和WorkflowRuntime 关联的名字。Workflow 运行时正在运行中你不能

    设置这个属性(也就是说当IsStarted 为True)。企图这样做的结果就是抛出一个“InvalidOperationException”异常。


表2-2 WorkflowRuntime 的方法


方法     功能

AddService

    为workflow 运行时添加指定的服务。能添加的服务类型和时间受到种种限制。关于服务的详细信息将在第五章介绍。

CreateWorkflow

    创建一个workflow 实例,它包含一些指定(但可选)的参数。假如workflow运行时没有启动,该方法就调用StartRuntime 方法。

GetWorkflow

    通过 指明workflow 实例的标识符(由一个Guid 组成)来检索workflow 实例。假如这个workflow 实例是空闲和持久化保存的,它将被重新加载并执行。

StartRuntime 启动workflow 运行时和相关服务,并引发“Started”事件。

StopRuntime 停止workflow 运行时和相关服务,并引发“Stoped”事件。

还有更多的关于WorkflowRuntime 的方法,但表2-2 中列出的方法是最经常用到的方法,也是我们将重点关注的方法。在workflow 运行期间,WorkflowRuntime 也将在各种时间引发许多事件,但我们将在后面的章节中介绍。


创建一个Workflow 运行时工厂


单 例和工厂设计模式的组合是强大的,因为工厂能保证只创建出一个曾创建的对象的单一实例,这正好符合我们的要求(在这里使用单例模式的原因主要是从效率上考 虑,其次一个应用程序域也只能只有一个WorkflowRuntime),因为WorkflowRuntime 完全有可能在不同的应用当中加载和启动(例 如独立的应用模块)。让我们看看怎样创建一个

WorkflowRuntime 工厂。

一、在项目中添加一个类型为类的新项,文件名为WorkflowFactory.cs。

二、在WorkflowFactory.cs 源文件中添加如下的引用

using System.Workflow.Runtime;

三、在类中添加下面的代码:

//workflow runtime 的单一实例
private static WorkflowRuntime _workflowRuntime = null;
private static object _syncRoot = new object();

四、在上述代码后添加如下方法:

//工厂方法
public static WorkflowRuntime GetWorkflowRuntime()
{
//多线程环境下防止并发访问
lock (_syncRoot)
{
if (null == _workflowRuntime)
_workflowRuntime = new WorkflowRuntime();
}
return _workflowRuntime;

五、为类加上Public 关键字,为防止类被直接实例化,还必须为类加上static 标记,

如下所示:

public static class workflowFactory


启动workflow 运行时


参 考表2-2,里面有一个StartRuntime 方法,从我们的工厂对象中调用这个方法很有意义,外部对象要求workflow 运行时对象无需处理或担心 运行时环境状态的初始化。我们

需要在我们的应用程序通过这一步来建立我们需要的workflow 环境。外部调用对象也需要workflow 运行时对象易于 使用。

并不是一定要调用StartRuntime。假如我们建立了一个workflow 实例,StartRuntime实际上就已被调 用。假如我们曾经创建了一个workflow 实例,或许并不用担心需要明确的

调用StartRuntime。但是,一旦我们添加服务时,明确地调用它就很 有必要,因为可增强代码的可维护性并确信运行时环境的状态已建立,这样任何人就都能使用workflow 运行时对象。

因此让我们在我们的工厂对象中做些轻微的更改并直接调用StartRuntime。

1.打开WorkflowFactory.cs 文件并定位到下面的代码上:

_workflowRuntime = new WorkflowRuntime();


2.在上面的代码下添加以下的代码:

_workflowRuntime.Starttime();

停止workflow 运行时是 否有办法启动一个workflow 运行时很有意义,如何停止一个workflow 运行时也一样。


看看表2-2 吧,里面有一个StopRuntime 方法正 好符合我们要求。调用StopRuntime 方法会卸载所有正执行的workflow 和服务并关闭workflow 运行时环境。当然,正确调用

StopRuntime 位置是在你申请停止逻辑结束之前或者应用程序域关闭前调用。

1.打开WorkflowFactory.cs 文件并定位到下面的代码上

_workflowRuntime = new WorkflowRuntime();

2.在上面代码的前面增加以下代码:

_workflowRuntime.Starttime();

3.在WorkflowFactory.cs 中增加StopWorkflowRuntime 事件处理函数:

static void StopWorkflowRuntime(object sender, EventArgs e)
{
if (_workflowRuntime != null)
{
if (_workflowRuntime.IsStarted)
{
try
{
_workflowRuntime.StopRuntime();
}
catch (ObjectDisposedException)
{
}
}
}
}

以下是WorkflowFactory.cs 文件的完整源代码,在第五章之前我们不会做更多的改变:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Workflow.Runtime;
namespace WorkflowHost
{
    public static class WorkflowFactory
    {
        //workflow runtime 的单一实例
        private static WorkflowRuntime _workflowRuntime = null;
        private static object _syncRoot = new object();
        //工厂方法
        public static WorkflowRuntime GetWorkflowRuntime()
        {
            //多线程环境下防止并发访问
            lock (_syncRoot)
            {
                if (null == _workflowRuntime)
                {
                AppDomain.CurrentDomain.ProcessExit += new EventHandler(StopWorkflowRuntime);
                AppDomain.CurrentDomain.DomainUnload += new EventHandler(StopWorkflowRuntime);
                _workflowRuntime = new WorkflowRuntime();
                _workflowRuntime.StartRuntime();
                }
            }
            return _workflowRuntime;
        }
        
        static void StopWorkflowRuntime(object sender, EventArgs e)
        {
            if (_workflowRuntime != null)
            {
                if (_workflowRuntime.IsStarted)
                {
                    try
                    {
                        _workflowRuntime.StopRuntime();
                    }
                    catch (ObjectDisposedException)
                    {
                    }
                }
            }
        }
    }
}

现在我们有了一个workflow 运行时的创建工厂,然后我们将修改我们的主程序来使用它。

使用workflow 运行时创建工厂

1.打开Program.cs 文件并定位到如下代码上:

    WorkflowRuntime workflowRuntime=new WorkflowRuntime();

2.把上面的代码修改成以下代码:

    WorkflowRuntime workflowRuntime=WorkflowFactory.GetWorkflowRuntime();

表2-3 workflow 运行时的相关事件描述

image.png

image.png

我们还将在第四章和第五章介绍更多的事件。

在我们为上面的事件添加相应的事件处理程序时,你会看到生成的代码和上一章我们创建的基于工作台的顺序工作流应用程序中的代码完全一样(或几乎完全一 样)。为了看看这

些事件的作用,我们需要停止应用程序主线程一段时间。因此,我们使用一个基于内核的自动重置事件。一会儿后,我们将写出一些代码来使用上 述事件中的几个,你需要不时看看第一章中PCodeFlow 项目中的Program.cs 文件,对比它们的不同以及该写入什么样的代码。尽管它们并不完全 相同,但你在两个程序中还是能找到相同的内容。


处理workflow 运行时事件

1.启动Visual Studio,打开项目的Program.cs 源文件,定位到下面的代码上:

WorkflowRuntime workflowRuntiem=WorkflowFactory.GetWorkflowRuntime();


2.假如你用过.NET 的委托,下面的代码你将非常熟悉。我们需要为我们感兴趣的事件增加相应的事件处理程序。我们现在就来为workflow 空闲时和完 成后增加相应的事件处理程

序。稍候我们还会增加我们所需要的更多的事件处理程序。记住,下面的代码在步骤1 定位的代码的下面:

workflowRuntime.WorkflowIdled += new

EventHandler<WorkflowEventArgs>(workflowIdled);


3.下面的代码添加了对workflow 完成后的事件处理:

workflowRuntime.WorkflowCompleted += new

EventHandler<WorkflowCompletedEventArgs>(workflowCompleted);


4.现在添加对workflow 终止后的事件处理:

workflowRuntime.WorkflowTerminated += new

EventHandler<WorkflowTerminatedEventArgs>(workflowTerminated);


5.假如你编译并运行WorkflowHost(本项目),这个应用程序能通过编译并运行。但没有执行workflow,因为我们并未告知 workflow 运行时去启动一个workflow 实例(我们将在下章添加)。为以后做准备,我们还要添加一些代码。首先,为了激发workflow 中的 事件

(以便我们观察它们),我们需要停止主线程足够长的时间,因此我们还将添加自动重置事件。在步骤3、4 的代码下添加以下代码。

Console.WriteLine("对待workflow 完成。");
waitHandle.WaitOne();
Console.WriteLine("完成.");

6.在Main 方法前定义一个名为waitHandle 的静态成员:

private static AutoResetEvent waitHandle = new AutoResetEvent(false);


7.添加名称空间:

using System.Threading;


8.由Vistual Studio 2008 创建的上面三个事件对应的事件处理程序内都包含“throw new NotImplementedException();”。我们需要移除这些代码并定位到workflowIdled

的事件处理程序内,写入下面的代码:

Console.WriteLine("workflow 实例空闲中");


9.定位到workflowCompleted 的事件处理程序内,写入下面的代码:

Console.WriteLine("workflow 实例已完成");

waitHandle.Set();


10.定位到workflowTerminated 的事件处理程序内,写入下面的代码:

Console.WriteLine("workflow 实例已终止,原因:'{0}'。",e.Exception.Message);

waitHandle.Set();


完整的代码见列表2-2。

列表2-2 WorkflowHost 应用程序的完整代码


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Workflow.Runtime;
using System.Threading;
namespace WorkflowHost
{
    class Program
    {
        private static AutoResetEvent waitHandle = new AutoResetEvent(false);
        static void Main(string[] args)
        {
            WorkflowRuntime workflowRuntime = WorkflowFactory.GetWorkflowRuntime();
            workflowRuntime.WorkflowIdled += new EventHandler<WorkflowEventArgs>(workflowRuntime_WorkflowIdled);
            workflowRuntime.WorkflowCompleted += new EventHandler<WorkflowCompletedEventArgs>(workflowRuntime_WorkflowCompleted);
            workflowRuntime.WorkflowTerminated += new EventHandler<WorkflowTerminatedEventArgs>(workflowRuntime_WorkflowTerminated);
            Console.WriteLine("等待workflow 完成。");
            waitHandle.WaitOne();
            Console.WriteLine("完成.");
        }
        
        static void workflowRuntime_WorkflowIdled(object sender, WorkflowEventArgs e)
        {
            Console.WriteLine("workflow 实例空闲中");
        }
        static void workflowRuntime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
        {
            Console.WriteLine("workflow实例已完成");
            waitHandle.Set();
        }
        static void workflowRuntime_WorkflowTerminated(object sender, WorkflowTerminatedEventArgs e)
        {
            Console.WriteLine("workflow 实例已终止,原因:'{0}'。",e.Exception.Message);
            waitHandle.Set();
        }
    }
}


下一章我们将深入workflow 实例,假如现在你执行这个程序,他会一直挂起。为什么呢?

因为我们从未执行一个workflow 实例,因此我们加入的事 件的从未被激发,也就未执行对应的事件处理程序。程序将永远挂起(或者你亲自终止它)。在下一章中当我们添加一个workflow 实例并执行它时我们还会 看到这个程序。


源码下载 http://files.cnblogs.com/gyche/WorkflowHost.rar



--------------------- 

作者:hackpig

来源:www.skcircle.com

版权声明:本文为博主原创文章,转载请附上博文链接!


本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年4月    »
1234567
891011121314
15161718192021
22232425262728
2930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864