你还记得windows workflow foundation吗

简介: 很多年前,windows workflow foundation还叫WWF,而直译过来的名称让很多人以为它就是用来开发工作流或者干脆就是审批流的。 博主当年还是个懵懂的少年,却也知道微软不会大力推一个面向如此具象的业务场景的技术,于是特地找了一本《WF本质论》,当看到“程序即数据”这个论断时,被深深震撼了。

很多年前,windows workflow foundation还叫WWF,而直译过来的名称让很多人以为它就是用来开发工作流或者干脆就是审批流的。

博主当年还是个懵懂的少年,却也知道微软不会大力推一个面向如此具象的业务场景的技术,于是特地找了一本《WF本质论》,当看到“程序即数据”这个论断时,被深深震撼了。可能这只是作者的随意一写,但当时正是泛型方法、lamda表达式、匿名委托啥的开始出现的时候,作者的这一说法在某种程度上暗合了博主平常的编程思想。于是逻辑与数据,算法与结构,它们之间的界限在我眼里,在我心里,开始以更诡异的方式模糊了起来。

然而之后并未在工作上使用过WF,因此博主也就不再关注此项技术。如今重新翻看,突然发现官方的Workflow Team blog最近的更新都是两年前了,网上的资料都是N年前的,而且大多数是教大家怎么用。为何要用,何处要用,基本上没有太多介绍。到了现如今,似乎也被微软抛弃了,为此我还专门在博问里提了下,也没人知道具体详情。

很少有看到专门使用wf进行开发的场景,好用与否,在小众的群体里抽样得出结论也就显得不怎么可靠了。似乎wf在sharepoint环境中用起来比较协调,由于博主对sharepoint没有研究过,所以对此不好评论。如若在纯代码环境下开发,用wf自带的一套activity能画出看似清晰的流程图,然而关键的和外部交互的环节却仍然避免不了,需要考虑的因素大部分仍然需要代码去完成;而各种条件下流程的走向,使用activity的条件判断,又让人觉得没有直接写代码来的方便,比如ifelse,用代码可能只要在一个方法体中就能完成,而在流程图中却要使用两个activity,如果其中再有交互跳转的话,流程图的复杂程度未必在代码之下,而后期维护也难说容易。

不妨非恶意的揣测,经过几年时间,微软慢慢觉得,将代码间原本隐晦的逻辑关系抽离出来变成看得见的“流程”,对程序员来说,未必有多大的意义,于是就减少了这方面的投入。当然你也可以认为wf已经很成熟了,不过即使如此,博主还是倾向认为此种所谓成熟是因为找不到改进的方向,虽然“成熟”,但不怎么好用。

but,wf并非一无是处,wf的bookmark(书签机制)是最区别于传统开发的特性,个人认为也是最重要的特性。传统开发时,我们时不常的会遇到这种情形:判断流程是否走到特定环节以便决定下一步操作,其实就是判断A\B\C\D\...等排列组合变数,它们之间可能也是相互关联的,只要流程没有继续流转,那么每次启动都要进行同样的判断;是否可以在各变数满足条件时生成一个标签,当我们发现这个标签存在时,就可以去找标签对应的环节,就能马上进行后续操作了。实际开发中,我们常设置一个冗余的标识字段起这个作用。但单个字段未必能完全标识一个环节,而且也显得不够直观。wf中的bookmark与上述的标签类似,本质上,它是对委托异步回调炉火纯青的应用,更自然的描述是在变数尚未符合条件时的一种“等待”,常用于与外部交互,在流程设计时,也不会像传统代码操作(查询、判断、更新)标签那样显得突兀(这些操作wf都在更底层帮我们处理了)。

开头说到微软推出wf的本意并非用于开发业务上的工作流,我们甚至可以将任意有逻辑顺序的一段代码“wf化”,然而从业务场景来讲,wf的很多概念能映射其中,毕竟抽象和具象,都逃不离流程二字。因此项目前期或工期紧张,需要快速开发的时候,wf也能帮助程序员梳理流程——在[对]业务流程尚不清晰的时候,你会发现这非常有用——就算日后摈弃wf,大部分代码都可以复用,而由于各环节明确的流转关系,代码重构也较为容易。博主就是因为这个原因,在目前的一个项目中使用了wf,下面我会简单介绍相关要点和个人理解。

版本控制也是它的一个亮点,这个就不细说了。

由于本人对wf钻研不深,所述难免有误,请各位同学批评指正。另,本文并不展示任何项目代码,只以行业一般流程,展示博主在开发过程中的思索。


本项目主干是一手房置购流程,涉及到认筹、认购、成交、租赁四个环节,需求简化后如下(图是用visio画的,画得很挫,一直没找到实线弧形箭头):

1、环节流转

2、流转时需审核(可跨级审核,若申请人本身是最后环节审核人则直接通过)

3、审核不通过时将退回发起环节;审核过程中,申请人也可撤消此次申请

4、单个环节也有不同状态,比如认购有已认购退认购两种状态,此类状态转换也需要审核;而内容变更也需要审核

5、同时至多只能存在一个审核中事项。比如认购内容变更审核中时,就不能发起转成交申请。

这是一个比较典型的工作流场景。刚接手这个项目时,我考虑用传统方式开发,不多久我发现自己在各种环节、状态、标识、互斥项间晕头转向,一团浆糊。即使流程图已经很清晰明白地摆在面前,将之赋予代码和数据,并使看似毫无关联的各块内容按照预期逻辑运行,似乎显得相当困难。特别是产品有时会一脸无奈地跟你说,认筹也可以转租赁,业务说的;隔天又说,不需要了。要维系代码之间“隐秘”的逻辑关系并快速应对需求变更,随着业务复杂度的提高,难度也更快的升高。

当然,对于熟练工来说,这点难度不算什么,毕竟我们每天都在做这种工作——将业务流程转化成层层调用的代码——我们还可以祭出设计模式、AOP、IOC、ORM啥的让代码看起来更清(fu)晰(za)。我们一直在接受面向对象、面向架构、面向服务的训练,而缺少真正面向流程编程的经验,我想这才是为什么微软当年会推广wf的原因(此为病句,意为强调)。

wf有三种内置流程:顺序流、Flowchart、StateMachine。本项目可考虑后两种,博主选择的是StateMachine,整出来的主流程如下:

看上去很凌乱,只能怪vs自带的wf设计器没有visio好用,其实上图就是第1幅流程图的wf版本。

再来看下每条连线的逻辑,以认购环节出去的连线为例,触发器如下:

可以看到,流程会依据外部信号决定下一步骤,流到下一个环节(转成交、转租赁),或者是退认购,这里还有变更的情况图中没放出来。最终会根据流程中各变量和参数值选择某个路线:

任何类型的审核不通过or申请人撤销就回到当前环节,和之前我们用visio画的流程图一样直观。不过,这里有个问题。博主刚接触statemachine时,选择entry还是trigger放置业务逻辑比较困惑,当时认为两者皆可,毕竟最终只是通过condition来指定状态的转变方向,用不着care condition在哪里生成;博主当时认为微软设计statemachine时,是将trigger当做bookmark activity的容器,以便于与外部决策进行交互,当然我们也可以将bookmark放在entry中,说到底这就是一个规范问题,不必深究。然而博主发现,若流程从一个state流向同一个state——即state指向自己——其实前后两个环节已不是同一个“实例”了 ,因此原state的变量等状态不会保存,entry会再次执行。为了避免这种状况,有停留在当前状态的情形,应该将业务逻辑写在entry中,不进入到触发后的流转,因为一旦流转,就算流转回当前状态,也是先出再进。当然,如果当前状态没有需要保留的信息,写在trigger亦可。

再来看看审核到底发生了什么。

这个更不用我多说了,不过我还是要多说两句。虽然上图很清晰地还原了对应的需求,但未必是最合适的做法,我最后还是将这些逻辑统一到一个activity里。前面说过,我们能将绝大多数多行代码wf化,but,复杂的流程需要借助wf,一个简单方法就能搞定的逻辑如果还硬要画出几道条条理理来,那就是偏执了。(话说,写程序的大多数人都是偏执的,非黑即白,我没说错吧)

对于前述需求的第5条,单条wf流程天生就能满足,不需要我们做额外的coding。思考一下,若几个审核可以并行,或流程流转到下一环节后,上一环节需要变更了,怎么办?用多流程或子流程试试吧。


代码活动中普通的成员变量,持久化在bookmark恢复后,值丢失不可用;若需要在持久化前后保持变量值,应该使用Variable,或应用Serializable特性,两者都是博主推测没试过。

有些事务不能失败了就全部回退重来,比如单据状态从a->b,经过多位领导审批同意后,结果因为最后一步提交不成功,让单据回退到a重审?这种情况,只能将最后一步重新提交,实际开发中,可将此类“脏提交”定时再提交。

一个activity里可create多个bookmark,当所有bookmark都恢复执行后,流程才继续往下。

wf在流程流转过程中,并不能返回数据给调用者,比如发起认筹转认购的申请,调用ResumeBookmark方法,并不能知晓是直接通过还是等待审核,需要另外查数据库得到状态结果。当然可以使用WorkflowApplication.Extensions与外部程序交互,但不能满足某些场景,比如客户端调用webapi,服务端action发起流程,action自然需要知道流程跑完后(暂停or完结)的结果是什么并返回给客户端;这时候WorkflowApplication.Extensions就然并卵了,除非改写底层,比如让wf能取消action的后续执行并将结果数据写入http连接。

流程改版or外部依赖项变化,wf下,要么新旧版本并行,要么研究如何将旧版本迁移到新版本,很多情况下没有纯代码控制来得方便。

博主观点:同步SaaS并非wf较适用的场景,wf适用于异步消息推送场景,比如外卖点餐状态、快递状态、银行资金流转等,客户端并不等待马上的结果,而是事项状态改变时接收服务端消息即可。当然硬要在同步环境下使用也可以,此时需要更松散的设计和底层框架的配合,以适应wf“封闭式流程”的特点。


需继续研究的点:

1、有些流程大同小异,能否封装成一个可配置的流程,在设计时进行简单的参数配置就能显示不同的流程步骤;比如a状态可转为b、c状态,而b只能转c状态,那么a,b在转换到下一个环节的判断逻辑就有少许差异了。这貌似只能通过元数据实现。

2、InstanceOwner,网上实在找不到更多关于它的介绍,目前可知是用于多宿主环境下,宿主对wf实例的lock。没找到给实例赋值InstanceOwner的直接途径,网上找到的基本上是下面两行代码:

InstanceView view = instore.Execute(instore.CreateInstanceHandle(), new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(30));
instore.DefaultInstanceOwner = view.InstanceOwner;

不知是基于什么因素考虑,总是觉得不太理解是什么意思,为什么要以及以这种方式设置DefaultInstanceOwner,如果不设置的话,那么下面这行代码运行时就会报错:

WorkflowApplicationInstance instance = WorkflowApplication.GetInstance(Guid.Parse(flowinstance.InstanceID), instore);

框架应该完全可以在底层就自动给我们处理InstanceOwner相关的东东,比如下面这句在没设置DefaultInstanceOwner的时候就不会报错:

wfApp.Load(Guid.Parse(flowinstance.InstanceID));

如何能设置自己的InstanceOwner呢,maybe可以通过InstanceOwnerMetadata。

CreateWorkflowOwnerCommand createCommand = new CreateWorkflowOwnerCommand()
{
    InstanceOwnerMetadata =
    {
        { WorkflowHostTypeName, new InstanceValue(WFInstanceScopeName) },
    }
};

不过设置完了,怎么获取又是一个问题,有兴趣的朋友可以研究下这个文件,也可以在官方WF_WCF_示例里找到。总之持久化这趟子水够深。

 

其它参考资料:

Loading persisted workflow instances with WorkflowApplication

目录
相关文章
|
4月前
|
vr&ar C# 图形学
WPF与AR/VR的激情碰撞:解锁Windows Presentation Foundation应用新维度,探索增强现实与虚拟现实技术在现代UI设计中的无限可能与实战应用详解
【8月更文挑战第31天】增强现实(AR)与虚拟现实(VR)技术正迅速改变生活和工作方式,在游戏、教育及工业等领域展现出广泛应用前景。本文探讨如何在Windows Presentation Foundation(WPF)环境中实现AR/VR功能,通过具体示例代码展示整合过程。尽管WPF本身不直接支持AR/VR,但借助第三方库如Unity、Vuforia或OpenVR,可实现沉浸式体验。例如,通过Unity和Vuforia在WPF中创建AR应用,或利用OpenVR在WPF中集成VR功能,从而提升用户体验并拓展应用功能边界。
90 0
|
4月前
|
开发者 C# Windows
WPF与游戏开发:当桌面应用遇见游戏梦想——利用Windows Presentation Foundation打造属于你的2D游戏世界,从环境搭建到代码实践全面解析新兴开发路径
【8月更文挑战第31天】随着游戏开发技术的进步,WPF作为.NET Framework的一部分,凭借其图形渲染能力和灵活的UI设计,成为桌面游戏开发的新选择。本文通过技术综述和示例代码,介绍如何利用WPF进行游戏开发。首先确保安装最新版Visual Studio并创建WPF项目。接着,通过XAML设计游戏界面,并在C#中实现游戏逻辑,如玩家控制和障碍物碰撞检测。示例展示了创建基本2D游戏的过程,包括角色移动和碰撞处理。通过本文,WPF开发者可更好地理解并应用游戏开发技术,创造吸引人的桌面游戏。
225 0
|
4月前
|
C# Windows 开发者
当WPF遇见OpenGL:一场关于如何在Windows Presentation Foundation中融入高性能跨平台图形处理技术的精彩碰撞——详解集成步骤与实战代码示例
【8月更文挑战第31天】本文详细介绍了如何在Windows Presentation Foundation (WPF) 中集成OpenGL,以实现高性能的跨平台图形处理。通过具体示例代码,展示了使用SharpGL库在WPF应用中创建并渲染OpenGL图形的过程,包括开发环境搭建、OpenGL渲染窗口创建及控件集成等关键步骤,帮助开发者更好地理解和应用OpenGL技术。
346 0
|
4月前
|
存储 开发者 C#
WPF与邮件发送:教你如何在Windows Presentation Foundation应用中无缝集成电子邮件功能——从界面设计到代码实现,全面解析邮件发送的每一个细节密武器!
【8月更文挑战第31天】本文探讨了如何在Windows Presentation Foundation(WPF)应用中集成电子邮件发送功能,详细介绍了从创建WPF项目到设计用户界面的全过程,并通过具体示例代码展示了如何使用`System.Net.Mail`命名空间中的`SmtpClient`和`MailMessage`类来实现邮件发送逻辑。文章还强调了安全性和错误处理的重要性,提供了实用的异常捕获代码片段,旨在帮助WPF开发者更好地掌握邮件发送技术,提升应用程序的功能性与用户体验。
77 0
|
C# Windows
Windows Presentation Foundation (WPF)中的命令(Commands)简述
原文:Windows Presentation Foundation (WPF)中的命令(Commands)简述 -----------------------------------------------------...
832 0
|
1月前
|
网络安全 Windows
Windows server 2012R2系统安装远程桌面服务后无法多用户同时登录是什么原因?
【11月更文挑战第15天】本文介绍了在Windows Server 2012 R2中遇到的多用户无法同时登录远程桌面的问题及其解决方法,包括许可模式限制、组策略配置问题、远程桌面服务配置错误以及网络和防火墙问题四个方面的原因分析及对应的解决方案。