NET 4.5 中状态机工作流
NET 4.5 中状态机工作流
结尾的总结有点与本文主题不符,是写文章时想到的,就顺手写上了(^_^)\
例子下载:
https://files.cnblogs.com/foundation/Wxwinter.Test.Statements.rar
介绍
.NET 4.5 中WF已为原WF4.0提供了状态机模式的支持.
先看一下增加加的Activity
使用VS2011创建WorkFlow项目,选 .NET 4.5 的WF模板
在WF设计界面可以看到状态机模板
由3个Activity组成
StateMachin 是状态机容器
State 是状态节点
FinalState 是结束状态节点
在State 中具有[进入状态],[结束状态]两个执行区,可以添加任意Activity,
FinalState 中具有[进入状态]
State可以添加多条分支,在分支上可以设置[Trigger],[Condition],[Action],这些与WF4.0中其他条件类Activity设置一样
例子
用一个例子演示一下状态机的使用
流程业务模型
设计书签
public sealed class resultBookmark : NativeActivity<string> {
public InArgument<string> bookmarkName { get; set; }
protected override bool CanInduceIdle { get
{ return true; }
}
protected override void Execute(NativeActivityContext context) {
string bookmark = context.GetValue(bookmarkName);
context.CreateBookmark(bookmark, new BookmarkCallback(bookmarkCallback));
System.Console.WriteLine("创建bookmark:{0}", bookmark);
}
void bookmarkCallback(NativeActivityContext context, Bookmark bookmark, object obj) { if (obj != null) { this.Result.Set(context, obj.ToString()); } else {
this.Result.Set(context, string.Empty); }
}
} |
在设计界面用WF构建业务模型
设计State,以[A]节点为例,其他类似
设计宿主
void workflowCompleted(WorkflowApplicationCompletedEventArgs e) { instance = null; System.Console.WriteLine("workflowCompleted:{0}", e.CompletionState.ToString()); }
void aborted(WorkflowApplicationAbortedEventArgs e) { instance = null; System.Console.WriteLine("aborted ,Reason:{0}", e.Reason.Message); }
UnhandledExceptionAction unhandledExceptionl(WorkflowApplicationUnhandledExceptionEventArgs e) { System.Console.WriteLine("unhandledException:{0}", e.UnhandledException.Message); return UnhandledExceptionAction.Cancel; } void workflowIdel(WorkflowApplicationIdleEventArgs e) { System.Console.WriteLine("Idle:{0}", e.InstanceId);
System.Console.WriteLine("--------BookmarkName---------------------------"); foreach (var item in e.Bookmarks) { System.Console.WriteLine("{0}", item.BookmarkName); } System.Console.WriteLine("================================"); } WorkflowApplication instance = null; |
private void startButton_Click(object sender, EventArgs e) { valueComboBox.Items.Clear(); valueComboBox.Items.Add("A"); valueComboBox.Items.Add("B"); valueComboBox.Items.Add("C"); valueComboBox.Items.Add("E"); valueComboBox.SelectedItem = "B";
instance = new WorkflowApplication(new myWorkflow());
instance.Completed = new Action<WorkflowApplicationCompletedEventArgs>(workflowCompleted); instance.OnUnhandledException = unhandledExceptionl; instance.Aborted = aborted; instance.Idle = workflowIdel; instance.Run(); } |
private void submitButton_Click(object sender, EventArgs e) { string bookName =bookmarkTextBox.Text; string inputValue = valueComboBox.SelectedItem.ToString();
if (instance != null) { if (instance.GetBookmarks().Count(p => p.BookmarkName == bookName) == 1) { instance.ResumeBookmark(bookName, inputValue); } else { foreach (var v in instance.GetBookmarks()) { System.Console.WriteLine("--------请从下面选项中选择一个BookmarkName---------------------------"); System.Console.WriteLine("BookmarkName:{0}:,OwnerDisplayName:{1}", v.BookmarkName, v.OwnerDisplayName); System.Console.WriteLine("================================"); } } } else { MessageBox.Show("没有创建实例"); } } |
测试
总结
这本是一个应在NET 4.0 中实现的功能,其实不谈数据结构与运行机制,FlowChar完全可以实现StateMachin 的所有业务逻辑.
只不过StateMachin 在VS设计器中给人一种更整洁的感觉,不过这只是展现层面的东西,之前不少人都实现过这种效果(包括我自已),理论上并不是很难,但由于WF4.0大部分的功能类从继承Object后就开始封闭与工程级保护,在这种情况下别说继承,就正常连引用都办不到,当然也有办法解决,不过实现后一般只做为概念展现,所以很多人在实际使用时采取的是自定义流程设计器,将FlowChar的结构展现成StateMachin ,通过拦截Bookmark实现[进入状态],[结束状态],其实这种工作量比传统意义上开发一套业务流程平台还有大,但为什么还有使用WF,这是很多人不理解的.其实使用WF的人基本分为两类,一类是具备设计器开发能力的人,看到VS中的WF设计界面后就觉得WF为其提供了一套拿来就能用的业务流程平台.这种想法是不对的,暂不分析WF是否只接适用用户业务,就常识来说,与WCF,WPF并列的WF怎么可能是直接面对业务用户的.另一类选择WF的人是看中了WF对状态的副本处理,事物处理,补偿处理这些从COM+延续下来的理念.很多时候我一直认为WCF +WF就是一个新版本的COM+
最后不得不提一下,虽然WF实现了FlowChar与StateMachin ,但其数据结构并不是图,而是树.如果既对Expression Tree熟悉,又对WF熟悉,你会发现Expression Tree就是一个WF数据结构精简版.谈到Expression Tree了解的人是多了,我也好解释了,这种数结构其实与内存中的栈管理方式很象,这就决定了调用只能指向栈开始,而不能任意指向栈的任意位置(不谈溢出,GOTO指针这个层面的问题).
为什么提上面这段内容,是因为我要说明由于这种数据结构我们很难现以下功能(这是一个业务功能,我先用C#风格有代码描述一下):
上面这段代码看起来有些疯狂,我们不从代码层面考虑(不加条件判断,不提动态编译,ICO,AOP),我只想这样写,我希望当程序运行到[24]时自动告诉我缺少哪个上下文(如obj),并让我补齐上下文后继续执行.
将这个问题业务化:
上车前要买票,(买票是上车的前置条件)
但我已经上了车却没买票,是补票还是将我赶下车买完票再上车.这就是经典的[补偿处理]机制
程序员说:"你们的业务总变,你们都说不清,让我们怎么开发"
客户说:"我们要是业务从来不变,每个人都能说清,要你们开发系统做什么"
数学是严谨的,而真实的业务到处充满了变通.如何用严谨的数学来构建变通业务的逻辑模型才是从事企业应用开发程序员所面临的问题