上篇文章介绍了使用WorkflowInvoker宿主创建和启动工作流,本篇文章继续介绍工作流宿主,上篇文章说过,WorkflowInvoker是个轻量级的工作流宿主,一般用于学习和开发环境,本文将介绍重量级的工作流宿主,也就是我们日常开发环境和应用环境中最常用的工作流宿主WorkflowApplication。
WorkflowInvoker只能提供简单的工作流创建和启动和简单的结束事件属性,为了弥补工作流运行过程中的监控、控制和持久化功能的缺陷,WF又推出了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(); }
运行结果如下:
说明:
首先,自定义一个非继承工作流控件类,需要继承NativeActivitt类,定义两个输入参数与一个输出参数,重写类的默认执行方法,将两个输入参数从流程上下文中取出来,将两个参数相加,获得操作结果作为输出参数放到流程上下文中。
主程序中,1 定义一个通用AutoResetEvent对象,以支持多线程;2 注册一个工作流流转完成时的事件,这个事件主要功能是获得输入参数,通过计算,打印输出参数及流程的一些参数;3 程序入口方法,定义一个字典,传入输入参数,定义工作流宿主对象,然后运行工作流,停止输出窗口,查看运行结果。
五 WorkflowApplication生命周期事件
编号 |
事件名称 |
功能 |
1 |
Aborted |
中止工作流事件 |
2 |
Completed |
工作流执行完成事件 |
3 |
Idle |
工作流进入空闲状态时执行的事件 |
4 |
Persistabledle |
工作流进入空闲状态且可被持久化时执行的事件 |
5 |
OnUnhandledException |
工作流实例发生未处理异常时执行的事件 |
6 |
OnUnloaded |
卸载工作流时执行的事件 |
//非继承自定义控件类,需要继承底层抽象基类 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(); }运行结果如下:
运行结果如下:
说明:定义一个自定义控件类,然后定义工作流中止时执行的事件,事件需要一个参数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(); }
说明:首先定义自定义控件类,然后定义卸载工作流时执行的事件,该事件需要一个参数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(); }
六 总结
WorkflowApplication提供了六个委托供我们在工作流运行状态时通过事件监控和控制工作流,我们需要按照我们的需求,合理的使用这些事件,只要我们理解了这六个事件的执行时间和委托的用法,我们一定可以使用工作流设计出更好的程序。