工作流系统中的语法标记系统

以微软的WF为基础,为达到ERP中的批核与通知目的,参考现有系统中的技术,在此分享其中的技巧。

先来看最终的结果,也就是下图中的工作流宿主。

image

在上面的工作流定义中,除工作流宿主(rehost)技术外,还需要解决规则表达式的解析难题。

.NET WF提供的规则编辑器是基于代码的,但对于一个无代码的开发环境,需要找到一种表达式的设计,解析规范。

比如,在运行时,我们需要根据当前的运行参数解析出以上表达式的分支,最终流向哪个批核结点。

经过摸索,我提供现有系统中已经应用的三种方案,供读者参考。

1 查询表达式

比如一个费用报销流程,当报销金额小于1000元时,可由部门主管直接批核。用SQL语句表达如下:

SELECT AMOUNT  FROM dbo.ICMOVH WHERE AMOUNT <1000  
AND REF_NO='<%InventoryMovementEntity.RefNo%>‘
 
<% 标记表示当前正在运行的业务对象,<%InventoryMovementEntity.RefNo%> 这一句可取到当前业务对象的标识值。再与金额条件Amount(小于等于1000)组合,当存在这样的单据时,即为满足分支条件,由部门主管批核。
 

2 查询语句

查询语句的作用是为了发送消息通知,将SQL命令通过参数化的方式封装,达到运行时获取数据的目的。
比如一个安全库存报警,当物料安全库存变动时,物料的库存余额小于当前物料设定的安全库存。
image 
为了查询数据,设计出一种新语法标记,例子如下:
<%RepeatEachRecord_Begin.SqlQuery1%> 
Job No: <%SqlQuery1.job_no%>
<%RepeatEachRecord_End.SqlQuery1%>

通过上图的界面设计中可看出,一个消息通知可包含很多个SQL命名查询,每个SQL命名查询可返回一个或多个数据行,我们在消息文本中用特定的语法,解析出命名查询中字段,即可达到获取数据的目的。

3 常量

工作流中的活动可理解为一个封装的独立的代码片段,为了与外界通信,必须向活动传递参数。有时候参数是固定的值,比如当前的报销单据,在前面我们用到过<%InventoryMovementEntity.RefNo%>表示报销单据编号。

若是要取到当前登录系统的用户,可用<%SessionEntity.UserId%>来获取。

比如给仓库单据增加一个验证,取出当前用户创建的引用(Reference)为空的参考编号。可通过下面的SQL语句实现:

SELECT RefNo  FROM dbo.ICMOVH WHERE REFERENCE IS NULL 
AND CREATED_BY='<%SessionEntity.UserId%>‘
 

4 调用程序代码

在一套业务工作流系统中调用代码实在是无奈之举。如果发生的业务很有规律,可考虑封装为活动以方便重用。

代码活动的表达方式如下:

image

我用了三行标记为的是表示一个.NET方法:
assembly=Microsoft.Workflow
class=Microsoft.Workflow.Extension
method=Microsoft.Workflow.Extension.VoucherPost
如果你熟悉.NET反射,很快能写出调用这个方法的代码。
Assembly assembly = null;
Type type = null;
string method = string.Empty;
List<string> format = new List<string>() { "assembly", "class", "method" };
string[] codes = Regex.Split(this.Code, ";");
foreach (string code in codes)
{
   if (string.IsNullOrWhiteSpace(code))
                    continue;
   string[] segments = Regex.Split(code, "=");
   if (Microsoft.Common.Shared.StringCompare(segments[0].ToUpper(), "assembly".ToUpper()) == 0)
         assembly = Assembly.Load(segments[1]);
   if (Microsoft.Common.Shared.StringCompare(segments[0].ToUpper(), "class".ToUpper()) == 0)
         type = assembly.GetType(segments[1]);
   if (Microsoft.Common.Shared.StringCompare(segments[0].ToUpper(), "method".ToUpper()) == 0)
        method = segments[1];
}
type.GetMethod(method, BindingFlags.Public | BindingFlags.Static).Invoke(null, null);
从最后一段代码中可以看出,上面标记的方法必须是静态(static,非实例)方法。
 
最后,我将前三种情况附加到程序中,以帮助对话框的形式提供给工作流开发人员。
image 
 
我这里所提到的工作流是以微软的WF为基础开发的一套工作流系统,如果你需要自定义一套工作流设计,业务开发,表达式解析等功能,文中的标记技术可供您参考。
 
posted @ 2016-05-09 23:30  信息化建设  阅读(842)  评论(0编辑  收藏  举报