Asp支持
todo
配置
目前,管道的配置使用ioc进行, 提供一个简单的图形界面也是可行的,你也可以手动配置一个管道。
Ioc配置例子一
<objects>
<object name="validateQuantity" class="ObjectsTest.ValidateQuantity"/>
<object name="validateFlowno" class="ObjectsTest.ValidateFlowNo"/>
<object name="pipeLine" class="sfc.PipeLine">
<property name="PipelineComponents">
<list>
<ref object="validateFlowno"/>
<ref object="validateQuantity"/>
</list>
</property>
</object>
</objects>
Ioc配置例子二—代理
<objects>
<object name="validateQuantityTarget" class="ObjectsTest.ValidateQuantity"/>
<object name="bug" class="sfc.DebugInterceptor"/>
<object name="timing" class="sfc.TimingInterceptor"/>
<object name="validateQuantity" class="sfc.PipelineComponentProxy">
<property name="Target"><ref object="validateQuantityTarget"/></property>
<property name="Interceptors">
<list>
<ref object="bug"/>
<ref object="timing"/>
</list>
</property>
</object>
<object name="validateFlowno" class="ObjectsTest.ValidateFlowNo"/>
<object name="pipeLine" class="sfc.PipeLine">
<property name="PipelineComponents">
<list>
<ref object="validateFlowno"/>
<ref object="validateQuantity"/>
</list>
</property>
</object>
</objects>
Ioc 配置三—这个配置说明了可以在管道上施加代理
<?xml version="1.0" encoding="GB2312" ?>
<objects>
<object name="validateQuantityTarget" class="ObjectsTest.ValidateQuantity"/>
<object name="bug" class="sfc.DebugInterceptor"/>
<object name="timing" class="sfc.TimingInterceptor"/>
<object name="validateQuantity" class="sfc.PipelineComponentProxy">
<property name="Target"><ref object="validateQuantityTarget"/></property>
<property name="Interceptors">
<list>
<ref object="bug"/>
<ref object="timing"/>
</list>
</property>
</object>
<object name="validateFlowno" class="ObjectsTest.ValidateFlowNo"/>
<object name="pipeLineTarget" class="sfc.PipeLine">
<property name="PipelineComponents">
<list>
<ref object="validateFlowno"/>
<ref object="validateQuantity"/>
</list>
</property>
</object>
<object name="pipeLine" class="sfc.PipeLineComponentProxy">
<property name="Target"><ref object="pipeLineTarget"/></property>
<property name="Interceptors">
<list>
<ref object="bug"/>
<ref object="timing"/>
</list>
</property>
</object>
</objects>
ComUnit测试代码
Dim ctx As IApplicationContext
Set ctx = createxmlapplicationcontext("c:\my works\sfc\test\pipeline3.xml")
Dim pipeline As IPipelineComponent
Set pipeline = ctx.GetObject("pipeLine")
oTestResult.Assert (TypeOf pipeline Is PipelineComponentProxy)
Dim proxy As PipelineComponentProxy
Set proxy = pipeline
oTestResult.Assert (TypeOf proxy.Target Is pipeline)
oTestResult.Assert (proxy.Interceptors.count = 2)
oTestResult.Assert (pipeline.Execute(Nothing, Nothing) = "success")
手动配置(摘自comunit测试代码)
Set pipeline = New pipeline
Dim c1 As IPipelineComponent
Set c1 = New ValidateFlowNo
Dim c2 As IPipelineComponent
Set c2 = New ValidateQuantity
Call pipeline.PipelineComponents.Add(c1)
Call pipeline.PipelineComponents.Add(c2)
手动配置—代理(摘自comunit测试代码)
Dim proxy As New PipelineComponentProxy
Set proxy.Target = New ValidateQuantity
Dim t As New TimingInterceptor
Dim di As New DebugInterceptor
Call proxy.Interceptors.Add(t)
Call proxy.Interceptors.Add(di)
Dim s As String
Call pipeline.PipelineComponents.Add(proxy)
s = pipeline.Execute(Nothing, Nothing)
oTestResult.Assert (LCase$(s) = "success")
oTestResult.Assert (di.count = 1)
'validateflowno sleep(5)
oTestResult.Assert (t.ElaspedTime >= 5)
应用
准备
业务过程分析
对业务过程进行分析,划分处理的步骤,一个步骤一个管道组件
可以预料的是,在一开始,通常只有一二个步骤,一般是规则验证,保存。随着开发的深入和用户需求的变更,管道步骤会增多。
Data,context约定
在配置每个管道前,首先要对管道中传递的数据进行约定。比方说,一个销售订单管道传递的数据是订单信息,至于这个数据是以class 还是用dictionary或是记录集。则根据具体情况而定,edf 没有强制要求
除了需要处理的数据外,还需要约定其它一些信息,比方错误信息的保存,其它的上下文信息。
在下面的例子中,context传递的是IapplicationContext 的实例,而data则是一个词典,其中有一个errors词典用来保存所有的错误信息
规则验证实例
一个实际例子,在一个计划单保存中,需要有两个验证过程
原vb 6代码
If ValidateQuantity = False Then
If MsgBox("颜色分配数量超过需要生产的数量,是否继续?", vbQuestion + vbYesNo, "提示") = vbNo Then
Exit Sub
End If
End If
If OrderService.ValidateFlowNo(orderid, txtFlowNo) Then
MsgBox "流程卡号不能重复", vbInformation, "提示"
txtFlowNo.SetFocus
Exit Sub
End If
这是个不好的例子,第一个规则在已有数据上展开,无需访问数据库,第二个例子需要访问数据库。
这里,就需要有两个组件,你可以选择用vb来实现,也可以使用Scriptor直接用脚本来实现。下面我们例子包括两者
启动管道
在这个例子中,data是一个词典,初始化的过程如下
Dim data as new dictionary
Set Data(“order”)=rsOrder
Set data(“gongyi”)=rsgongyi
Set data(“color”)=rsColor
Set data(“renyuan”)=rsrenyuan
Set data(“spoilage”)=rsSpoilage
Set data(“errors”)=new dictionary
Dim pipeline as IpipelineComponent
set pipeline=context.GetObject(“planPipeLine”)
If Pipeline.Execute(data,contenxt)=” failure” then
‘遍历错误词典,以了解详细信息
Msgbox “错误”
Else
Msgbox “执行结束”
End if
编写第一个管道组件实现
todo
编写第二个管道组件实现
todo
拦截器实现举例
Timing拦截器
Timing拦截器记录一个管道组件的执行时间
'##MODULE_SUMMARY 执行时间拦截器
Option Explicit
Implements IInterceptor
Private et As Long
'## 总执行时间
Public Property Get ElaspedTime() As Long
ElaspedTime = et
End Property
'## 执行拦截器
'##param invocation PipelineComponentInvocation实例
'##returns 执行结果
Private Function IInterceptor_Invoke(invocation As PipelineComponentInvocation) As String
Dim t As New Timing
t.start
IInterceptor_Invoke = invocation.Invoke
t.finish
et = t.ElaspedTime
Set t = Nothing
End Function
事务拦截器
事务拦截器需要使用edf的data框架,这个简单的拦截器具有两个属性
rollbackOnError 如果错误触发是否执行回退
rollbackName 这个定义那个返回值需要回退,默认是 rollback
代码
''##MODULE_SUMMARY 事务拦截器
Option Explicit
Implements IInterceptor
'## 定义回退的返回值,默认为rollback
Public RollbackName As String
'## 如果错误触发是否回退,默认为true
Public RollbackOnError As Boolean
'## ITransaction实例
Public Transaction As ITransaction
Private Sub Class_Initialize()
RollbackName = "rollback"
RollbackOnError = True
End Sub
'## 执行
Private Function IInterceptor_Invoke(invocation As PipelineComponentInvocation) As String
If Transaction Is Nothing Then
IInterceptor_Invoke = invocation.Invoke
Exit Function
End If
Transaction.BeginTransaction
Dim retval As String
retval = invocation.Invoke
If retval = RollbackName Then
Transaction.RollbackTransaction
Else
Transaction.CommitTransaction
End If
IInterceptor_Invoke = retval
Exit Function
sub_end:
Dim ex As Exception
Set ex = New Exception
If RollbackOnError Then Transaction.RollbackTransaction
ex.throw
End Function
例子配置
<objects>
<!-- 数据源-->
<object name="dataSource" class="sfc.SqlOledbDataSource">
<property name="server">(local)</property>
<property name="userid">sa</property>
<property name="database">mis2</property>
</object>
<!-- 事务对象 -->
<object name="transaction" class="sfc.AdoTransaction">
<property name="dataSource"><ref object="dataSource"/></property>
</object>
<!--事务拦截器-->
<object name="transactionInterceptor" class="sfc.TransactionInterceptor">
<property name="transaction"><ref object="transaction"/></property>
</object>
<!--管道组件-->
<object name="addCustomer" class="ObjectsTest.AddCustomer">
<property name="dataSource"><ref object="dataSource"/></property>
</object>
<object name="addCustomer2" class="ObjectsTest.AddCustomer">
<property name="dataSource"><ref object="dataSource"/></property>
</object>
<!--管道-->
<object name="pipeLineTarget" class="sfc.PipeLine">
<property name="pipelineComponents">
<list>
<ref object="addCustomer"/>
<ref object="addCustomer2"/>
</list>
</property>
</object>
<!-- 管道代理 -->
<object name="pipeLine" class="sfc.PipeLineComponentProxy">
<property name="Target"><ref object="pipeLineTarget"/></property>
<property name="Interceptors">
<list>
<ref object="transactionInterceptor"/>
</list>
</property>
</object>
</objects>
测试代码
Dim ctx As IApplicationContext
Set ctx = CreateXmlApplicationContext(App.Path & "\pipeline7.xml")
Dim dataSource As IDataSource
Set dataSource = ctx.GetObject("dataSource")
Dim sql As adotemplate
Set sql = New adotemplate
Set sql.dataSource = dataSource
Dim count As Long
Dim c As String
c = "select count(*) from customerinfo"
count = sql.ExecuteScalar(c)
Dim p As IPipelineComponent
Set p = ctx.GetObject("pipeLine")
oTestResult.Assert (p.Execute(Nothing, Nothing) = "success")
oTestResult.Assert (sql.ExecuteScalar(c) = (count + 2))
count = sql.ExecuteScalar(c)
'增加一个回退
Dim r As RollbackMock
Set r = New RollbackMock
Dim pl As pipeline
Set pl = ctx.GetObject("pipeLineTarget")
Call pl.PipelineComponents.Add(r)
oTestResult.Assert (p.Execute(Nothing, Nothing) = r.Result)
'没有变化
oTestResult.Assert (sql.ExecuteScalar(c) = count)
destroyxmlapplicationcontext ctx