探索工作流(五)--工作流宿主WorkflowApplication

        上篇文章介绍了使用WorkflowInvoker宿主创建和启动工作流,本篇文章继续介绍工作流宿主,上篇文章说过,WorkflowInvoker是个轻量级的工作流宿主,一般用于学习和开发环境,本文将介绍重量级的工作流宿主,也就是我们日常开发环境和应用环境中最常用的工作流宿主WorkflowApplication。


一 概述

        WorkflowInvoker只能提供简单的工作流创建和启动和简单的结束事件属性,为了弥补工作流运行过程中的监控、控制和持久化功能的缺陷,WF又推出了WorkflowApplication对象,本文从工作流创建、启动,工作流对象生命周期、执行控制等方面介绍。


二 对象说明
        WorkflowApplication
        命名空间:System.Activities
        程序集:System.Activities
        文件:System.Activities.dll
        结构说明:集成自WorkflowInstance,是个sealed类,不能被继承。

        功能说明:可以用来创建和启动、监控工作流,支持多线程。


三 结构详解

1 类图

探索工作流(五)--工作流宿主WorkflowApplication_第1张图片

2 属性和方法如下:

属性/方法

说明

Aborted

获取或设置中止工作流实例时调用的 Action<T>

Completed

获取或设置工作流实例完成时调用的 Action<T>

Unloaded

获取或设置卸载当前工作流时调用的 Action<T>

Idle

获取或设置当前工作流实例进入空闲状态时调用的 Action<T>

Unloaded

获取或设置卸载当前工作流时调用的 Action<T>

WorkflowDefinition

获取工作流实例的工作流定义

PersistableIdle

获取或设置当前工作流实例处于空闲状态并可执行持续化时调用的 ActivityFunc

Id

获取当前工作流的Guid标识

InstanceStore

持续化用到的状态对象

Run()

开始或恢复执行工作流实例

ResumeBookmark()

恢复因为创建了书签而处于Idle状态的工作流运行

Abort()

中止此工作流实例

Cancel()

取消工作流实例

CreateDefaultInstanceOwner()

使用指定实例存储、定义标识和标识筛选器和超时间隔,创建工作流的默认实例所有者

DeleteDefaultInstanceOwner()

使用指定的实例存储区和超时间隔检索工作流的可运行实例

GetBookmarks()

获取工作流实例的书签的集合

GetInstance(Guid, InstanceStore)

使用指定的实例标识符和实例存储区检索工作流实例

Load(Guid)

将指定的工作流实例从实例存储区加载到内存中

LoadRunnableInstance()

从示例存储区加载可运行的工作流实例

Persist()

持续化工作流

Terminate()

终止工作流的运行

Unload()

持续化并且卸载工作流实例(可再次用Load()方法加载运行)


四 创建和启动工作流

    //非继承自定义控件类,需要继承底层抽象基类
    public sealed class testActivity : NativeActivity
    {
        //定义两个输入参数和一个输出参数
        public InArgument<int> test1 { get; set; }
        public InArgument<int> test2 { get; set; }
        public OutArgument<int> testResult { get; set; }
        //自定义控件默认执行的方法
        protected override void Execute(NativeActivityContext context)
        {
            //从流程上下文中获得输入参数
            int t1 = test1.Get(context);
            int t2 = test2.Get(context);
            //计算后,将输出参数赋值,并且将输出参数传入到流程上下文
            context.SetValue(testResult, t1 + t2);
        }
    }

 class Program
    {
        //定义一个线程控制对象,以支持多线程
        public static AutoResetEvent synEvent = new AutoResetEvent(false);
        static void Main(string[] args)
        {
            //定义一个字典,用于传入输入参数
            Dictionary<string, object> dic = new Dictionary<string, object>();
            dic.Add("test1", 1);
            dic.Add("test2", 2);
            //定义工作流宿主对象
            WorkflowApplication application = new WorkflowApplication(new testActivity(), dic);
            //注册工作流流转结束时的事件
            application.Completed += workflowCompleted;
            //运行工作流
            application.Run();
            //阻塞当前线程
            synEvent.WaitOne();
            Console.ReadKey();
        }

        //注册工作流流转完成时调用的事件
        static void workflowCompleted(WorkflowApplicationCompletedEventArgs e)
        {
            //输出当前节点状态及工作流实例ID
            Console.WriteLine(e.CompletionState.ToString());
            Console.WriteLine(e.InstanceId.ToString());
            //打印输出参数
            e.Outputs.ToList().ForEach(p =>
                {
                    Console.WriteLine(p.Key.ToString());
                    Console.WriteLine(p.Value.ToString());
                });
            //设置当前事件状态,切换到主线程继续执行
            synEvent.Set();
        }

运行结果如下:

探索工作流(五)--工作流宿主WorkflowApplication_第2张图片

        说明:
        首先,自定义一个非继承工作流控件类,需要继承NativeActivitt类,定义两个输入参数与一个输出参数,重写类的默认执行方法,将两个输入参数从流程上下文中取出来,将两个参数相加,获得操作结果作为输出参数放到流程上下文中。
        主程序中,1 定义一个通用AutoResetEvent对象,以支持多线程;2 注册一个工作流流转完成时的事件,这个事件主要功能是获得输入参数,通过计算,打印输出参数及流程的一些参数;3 程序入口方法,定义一个字典,传入输入参数,定义工作流宿主对象,然后运行工作流,停止输出窗口,查看运行结果。


        五 WorkflowApplication生命周期事件

        

编号

事件名称

功能

1

Aborted

中止工作流事件

2

Completed

工作流执行完成事件

3

Idle

工作流进入空闲状态时执行的事件

4

Persistabledle

工作流进入空闲状态且可被持久化时执行的事件

5

OnUnhandledException

工作流实例发生未处理异常时执行的事件

6

OnUnloaded

卸载工作流时执行的事件


下面以三个事件为例,说明如何使用这些事件。
1 中止工作流事件

    //非继承自定义控件类,需要继承底层抽象基类
    public sealed class testActivity : NativeActivity
    {
        //定义两个输入参数和一个输出参数
        public InArgument<int> test1 { get; set; }
        public InArgument<int> test2 { get; set; }
        public OutArgument<int> testResult { get; set; }
        //自定义控件默认执行的方法
        protected override void Execute(NativeActivityContext context)
        {
            //从流程上下文中获得输入参数
            int t1 = test1.Get(context);
            int t2 = test2.Get(context);
            //计算后,将输出参数赋值,并且将输出参数传入到流程上下文
            context.SetValue(testResult, t1 + t2);
        }
    }

	//定义工作流终止状态时触发的事件
        static void workflowAborted(WorkflowApplicationAbortedEventArgs e)
        {
            //打印信息
            Console.WriteLine("Workflow {0} Aborted", e.InstanceId);
            Console.WriteLine("Exception:{0}\n{1}", e.Reason.GetType().FullName, e.Reason.Message);
            //设置当前事件状态为完成状态,切换到主线程
            synEvent.Set();
        }

    class Program
    {
        //定义一个线程控制对象,以支持多线程
        public static AutoResetEvent synEvent = new AutoResetEvent(false);
        static void Main(string[] args)
        {
            //定义一个字典,用于传入输入参数
            Dictionary<string, object> dic = new Dictionary<string, object>();
            dic.Add("test1", 1);
            dic.Add("test2", 2);
            //定义工作流宿主对象
            WorkflowApplication application = new WorkflowApplication(new testActivity(), dic);
            //注册工作流中止时的事件
            application.Aborted += workflowAborted;
            //运行工作流
            application.Run();
            //中止当前线程
            application.Abort();
            //阻塞当前线程
            synEvent.WaitOne();
            Console.ReadKey();
        }
运行结果如下:

探索工作流(五)--工作流宿主WorkflowApplication_第3张图片

        运行结果如下:
        说明:定义一个自定义控件类,然后定义工作流中止时执行的事件,事件需要一个参数WorkflowApplicationAbortedEventArgs,参数中包含了流程实例ID和异常信息,然后在主程序中手动中止流程,抛出异常。

        2 卸载工作流时的事件

    //非继承自定义控件类,需要继承底层抽象基类
    public sealed class testActivity : NativeActivity
    {
        //定义两个输入参数和一个输出参数
        public InArgument<int> test1 { get; set; }
        public InArgument<int> test2 { get; set; }
        public OutArgument<int> testResult { get; set; }
        //自定义控件默认执行的方法
        protected override void Execute(NativeActivityContext context)
        {
            //从流程上下文中获得输入参数
            int t1 = test1.Get(context);
            int t2 = test2.Get(context);
            //计算后,将输出参数赋值,并且将输出参数传入到流程上下文
            context.SetValue(testResult, t1 + t2);
        }
    }


	//定义工作流卸载时触发的事件
        static void workflowUnLoaded(WorkflowApplicationEventArgs e)
        {
            Console.WriteLine("InstanceID:{0}", e.InstanceId);
            synEvent.Set();
        }
            

	//定义一个线程控制对象,以支持多线程
        public static AutoResetEvent synEvent = new AutoResetEvent(false);
        static void Main(string[] args)
        {
            //定义一个字典,用于传入输入参数
            Dictionary<string, object> dic = new Dictionary<string, object>();
            dic.Add("test1", 1);
            dic.Add("test2", 2);
            //定义工作流宿主对象
            WorkflowApplication application = new WorkflowApplication(new testActivity(), dic);

            //注册工作流卸载时执行的事件
            application.Unloaded += workflowUnLoaded;

            //运行工作流
            application.Run();
            
            //阻塞当前线程
            synEvent.WaitOne();
            Console.ReadKey();
        }

运行结果如下:

探索工作流(五)--工作流宿主WorkflowApplication_第4张图片

        说明:首先定义自定义控件类,然后定义卸载工作流时执行的事件,该事件需要一个参数WorkflowApplicationEventArgs,参数中包含了流程实例ID信息,最后打印信息。
        3 工作流遇到未处理异常时的事件

    //非继承自定义控件类,需要继承底层抽象基类
    public sealed class testActivity : NativeActivity
    {
        //定义两个输入参数和一个输出参数
        public InArgument<int> test1 { get; set; }
        public InArgument<int> test2 { get; set; }
        public OutArgument<int> testResult { get; set; }
        //自定义控件默认执行的方法
        protected override void Execute(NativeActivityContext context)
        {
            //从流程上下文中获得输入参数
            int t1 = test1.Get(context);
            int t2 = test2.Get(context);
            //计算后,将输出参数赋值,并且将输出参数传入到流程上下文
            context.SetValue(testResult, t1 + t2);
        }
    }

	//定义一个线程控制对象,以支持多线程
        public static AutoResetEvent synEvent = new AutoResetEvent(false);
        static void Main(string[] args)
        {
            //定义一个字典,用于传入输入参数
            Dictionary<string, object> dic = new Dictionary<string, object>();
            dic.Add("test1", 1);
            dic.Add("test2", 2);
            //定义工作流宿主对象
            WorkflowApplication application = new WorkflowApplication(new testActivity(), dic);

            //运行工作流
            application.Run();

            application.OnUnhandledException = (ex) =>
                {
                    Console.WriteLine("ExceptionID:{0}", ex.ExceptionSourceInstanceId);
                    Console.WriteLine("InstanceID:{0}", ex.InstanceId);
                    Console.WriteLine("ExceptinoMessage:{0}", ex.UnhandledException.Message);
                    return UnhandledExceptionAction.Terminate;
                };
            

            //阻塞当前线程
            synEvent.WaitOne();
            Console.ReadKey();
        }

        说明:首先定义自定义控件类,异常类事件包含两个参数WorkflowApplicationUnhandledExceptionEventArgs和UnhandledExceptionAction,第一个参数包含了异常处理信息,第二个参数是个枚举类,里边的值分别为Abort,Cancle,Terminate,表示处理异常以后工作流状态,Abort为中止当前线程,Cancle表示取消当前线程,Terminate表示中止当前线程并恢复主线程。


        六 总结

        WorkflowApplication提供了六个委托供我们在工作流运行状态时通过事件监控和控制工作流,我们需要按照我们的需求,合理的使用这些事件,只要我们理解了这六个事件的执行时间和委托的用法,我们一定可以使用工作流设计出更好的程序。

你可能感兴趣的:(工作流事件,工作流运行参数,工作流与委托)