持久化服务
工作流并不是一个点击操作,在该操作结束以后用户马上就知道本次执行的结果。比如一个报销流程,实际中领导并不能立即审批,这时候这个运行一半的工作流就需要先保存到数据库或者硬盘文件中。当领导有时间审批报销单时,WF就可以将持续化后的工作流实例从数据库或硬盘上重新加载回工作流运行时容器中。
这就是WF提供的持久化服务,SqlWorkflowPersistenceService,它用来把工作流实例序列化进SQL SERVER数据库。
当工作流运行的时候发生特定情况时,工作流运行时引擎就会使用持久性服务(如果在运行时加载了持久性服务)保留有关工作流实例的状态信息。 这些情况包括:
1.当完成 TransactionScopeActivity 活动和 CompensatableTransactionScopeActivity 活动中的原子事务时。
2.当工作流实例空闲,且对 WorkflowPersistenceService 将 UnloadOnIdle 标志设置为 true 时。 例如,在使用 DelayActivity 活动时会发生此情况。
3.当运行时主机应用程序对工作流实例调用 System.Workflow.Runtime.WorkflowInstance.Unload或 System.Workflow.Runtime.WorkflowInstance.TryUnload 时。
4.当中止工作流实例或工作流实例结束时。
5.使用 PersistOnCloseAttribute 属性的自定义活动完成时。
如果满足这些条件之一且将持久性服务添加到运行时引擎,则运行时引擎会调用由持久性服务提供的方法,以保存关于工作流实例的状态信息。 同样,当工作流运行时引擎必须还原以前保留的工作流实例时,它调用由持久性服务提供的方法,以加载此状态信息。 换句话说,工作流实例决定持久性发生的时间,但持久性服务决定是否执行必要的持久性操作。
要在SQL Server数据库基础上实现工作流的持续化功能,因此需要在SQL Server数据库上创建相关数据表和存储过程,WF已经提供了相应的SQL脚本,默认情况下是路径:“C:\WINDOWS\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL\ZH-CHS\”的SqlPersistenceService_Logic.sql和SqlPersistenceService_Schema.sql两个文件。创建一个数据库(名字任意,比如WorkflowStore),在该数据库上运行这两个SQL脚本。运行结束以后,就会看到两个数据表和几个存储过程被创建:
我们能够通过WorkflowInstance对象的三个方法来控制上述的持久化:
WorkflowInstance方法
方法 | 功能 |
Load | 加载先前被卸载(持久化)的工作流实例 |
TryUnload | 试图从内存中卸载(持久化)该工作流实例。和调用Unload不同的是,调用TryUnload时假如工作流实例不能立即被卸载,那它将不会被阻塞(维持执行状态)。 |
Unload | 从内存中卸载(持久化)该工作流实例。注意该方法为进行卸载将阻塞当前执行的线程,直到工作流实例被真正地卸载。这可以是一个漫长的操作,这取决于个人的工作流任务。 |
Unload会暂停工作流实例来为其持久化做好准备。假如这要花费很长时间,该线程执行Unload操作也就要等待很长时间。然而,TryUnload在请求卸载一个执行中的实例时将立即返回,但这不能保证该工作流实例真正被卸载并持久化到数据库中。为进行检验,你应检查TryUnload方法的返回值。假如该值是true,该工作流实例本身就是卸载和持久化了的,假如该值是false,则该工作流实例还没有被卸载和持久化。TryUnload的优点是你的线程不会处在等待状态,当然缺点是你可能要对该执行中的工作流实例重复地使用TryUnload方法(进行检查)。
跟踪计时器
SqlWorkflowPersistenceService也负责管理跟踪计时器。比如,一个财务报销工作流给批准设定的时限是一个星期,就必须跟踪这个定时器,以保证如果一个星期后没有批准就将需要的工作流装在进来。
SqlWorkflowPersistenceService在它的SQL表里存储计时器的超时时限。当运行时开始、持久化服务装载好后,它最先做的事情就是扫描这些计时器时限,检查当宿主不可用时是否有丢失、这样,持久化服务保证即使宿主当机了,当重启后,任何超时的计时器都会得到处理。
跟踪服务
WF提供了Tracking跟踪功能来对工作流实例及其所包含的活动在运行时的状态进行跟踪,以便用户在需要的时候可以通过这些历史信息进行分析。相关的脚本在:C:\WINDOWS\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL\ZH-CHS下的Tracking_Schema.Sql文件和Tracking_Logic.Sql文件。
WF中的跟踪服务(1):Sql跟踪数据库表,视图,存储过程等相关说明
事件记录对象
对象 | 功能 |
指定要从活动中提取并在跟踪点匹配时与关联的批注集合一起发送到跟踪服务的属性或字段。 | |
ActivityTrackingCondition | 表示一个条件,该条件通过使用指定的比较运算符将活动成员的值与指定值进行比较。 |
ActivityTrackingLocation | 定义与根工作流实例的可能执行路径中的某个活动状态事件相对应的活动限定位置。 |
ActivityTrackingRecord | 包含运行库跟踪基础结构在 ActivityTrackPoint 匹配时发送到跟踪服务的数据。它还用在 ActivityEvents 属性的返回列表中。 |
ActivityTrackPoint | 定义工作流实例的可能执行路径中要跟踪的点,该点与活动执行状态更改关联。 |
SqlTrackingQuery | 包含用于管理跟踪数据查询的方法和属性,跟踪数据包含在 SqlTrackingService 使用的 SQL 数据库中。 |
SqlTrackingQueryOptions | 包含一些属性,这些属性用于约束 SqlTrackingQuery.GetWorkflows 调用所返回 SqlTrackingWorkflowInstance 对象的集合。 |
SqlTrackingWorkflowInstance | 通过工作流实例的 SqlTrackingService 提供对SQL数据库中保留的跟踪数据的访问 |
TrackingProfile | 定义根工作流实例的可能执行路径中的关注点,应将有关该关注点的信息通知跟踪服务。它过滤跟踪事件,并把过滤后的跟踪记录返回给某个跟踪服务。这里有三种类型的跟踪事件能被过滤:活动状态事件、工作流状态事件和用户事件。 |
UserTrackingLocation | 定义与根工作流实例的可能执行路径中的某个用户事件相对应的活动限定位置。 |
UserTrackingRecord | 包含运行库跟踪基础结构在 UserTrackPoint 匹配时发送到跟踪服务的数据。 |
UserTrackPoint | 定义一个要跟踪的点(与用户事件关联),该点位于根工作流实例的可能执行路径中。 |
WorkflowDataTrackingExtract | 指定要从工作流的根活动中提取,并在跟踪点匹配时随关联的批注集合一起发送到跟踪服务的属性或字段。 |
WorkflowTrackingLocation | 定义对发生在根工作流实例中的特定工作流事件的关注;用于按跟踪配置文件中的 WorkflowTrackPoint 进行匹配。 |
WorkflowTrackingRecord | 包含运行时跟踪基础结构在匹配了 WorkflowTrackPoint 时发送到跟踪服务的数据。它还用在 WorkflowEvents 属性的返回列表中。 |
WorkflowTrackPoint | 定义一个与一组工作流状态事件关联的点,这些事件在根工作流实例的可能执行路径中进行跟踪。 |
使用跟踪服务的典型代码:
这样在执行流程的时候就会自动记录信息。
跟踪会记录3中事件的信息,分别是活动状态事件(ActivityEvents)、工作流状态事件(WorkflowEvents)以及用户事件(UserEvents)。SqlTrackingWorkflowInstance类是我们访问指定工作流实例的跟踪信息的入口。它的ActivityEvents属性会返回一个ActivityTrackingRecord对象集合。同样的,WorkflowEvents属性会返回WorkflowTrackingRecord对象集合,UserEvents属性会返回UserTrackingRecord对象集合(UserEvents就是我们可以自定义的事件)。而且需要注意的是这些信息中还包含了时间戳、参数和状态代码。SqlTrackingWorkflowInstance类还包含了一个WorkflowDefinition属性,可以返回一个工作流的XAML定义,这个功能在审核使用了动态更新或者为每个客户端进行了定制的工作流时非常有用。下面的代码获得SqlTrackingWorkflowInstance:
SqlTrackingQuery sqlTrackingQuery = new SqlTrackingQuery(ConnectionString);
SqlTrackingWorkflowInstance sqlTrackingWorkflowInstance = null;
sqlTrackingQuery.TryGetWorkflow(instanceId, out sqlTrackingWorkflowInstance);
首先创建了一个SqlTrackingQuery的实例,为它提供了我们曾提供给SqlTrackingService的相同的连接字符串。然后我们通过当前工作流实例的ID(一个Guid)标识,从数据库中查询该实例的跟踪信息。该查询由SqlTrackingService.TryGetWorkflow执行。在确定数据库中有我们的信息以后,就可以通过相应的方法进行输出,比如输出实例的事件(获得活动的事件也是类似的,使用ActivityTrackingRecord
Code
if (sqlTrackingWorkflowInstance != null)
{
foreach (WorkflowTrackingRecord workflowTrackingRecord
in sqlTrackingWorkflowInstance.WorkflowEvents)
{
Console.WriteLine(" {0} :: {1}",
workflowTrackingRecord.TrackingWorkflowEvent, //工作流状态事件
workflowTrackingRecord.EventDateTime); //事件发生时的日期和时间
}
}
下面是一次运行结果的的截图,输出了活动事件和流程事件:
记录用户事件
活动和工作流激发的事件它都可以很好的记录,那么对于用户记录呢?Activity支持一个名叫TrackData的方法,它可以像将信息存储进数据库。在流程活动中,只要调用:
this.TrackData("message");
便会发现UserEvent表中有了记录。
跟踪逻辑判断活动
在前面我们已经了解到WF中有些活动时基于逻辑判断的,例如Policy活动。该活动可以根据用户定义的规则“Rule”来进行判断,并根据其结果来分别执行“Then Actions”和“Else Actions”中的操作。WF的Tracking功能同样也可以对基于逻辑判断活动所执行的判断结果进行跟踪。
SqlTrackingQuery sqlTrackingQuery = new SqlTrackingQuery(connectionString);
SqlTrackingWorkflowInstance sqlTrackingWorkflowInstance;
sqlTrackingQuery.TryGetWorkflow(instanceId, out sqlTrackingWorkflowInstance);
if (sqlTrackingWorkflowInstance != null)
{
foreach (UserTrackingRecord activityTrackingRecord
in sqlTrackingWorkflowInstance.UserEvents)
{
RuleActionTrackingEvent rule =
(RuleActionTrackingEvent)activityTrackingRecord.UserData;
this.ListViewWFEvent.Items.Add(new ListViewItem(new String[]
{ activityTrackingRecord.QualifiedName, //实例名称
rule.RuleName, //条件名称
rule.ConditionResult.ToString() //条件结果
}
));
}
}
跟踪配置
跟踪配置就是一组类型为WkflowTrack、ActivityTrackPoint或UserTrackPoint的跟踪点(tracking point)的集合。每一个跟踪点都由MatchingLocations(匹配地址)、ExcludedLocations(排除地址)、Extracts(摘记)、Annotations(注解)组成。
1.匹配地址:由一个类型(地址应用到得活动)、ExecutionStatusEvents(地址应用到的事件)和条件(在什么情况下会被应用)定义。
2.ExcludedLocations:专门制定什么时候不应该跟踪。
3.Extracts:定义了什么样的数据(活动的属性或者工作流)需要跟踪。
4.Annotations:当一个跟踪记录发出时需要包含的一组字符串。
下图演示了创建跟踪配置的相关类:
在上面的跟踪表中,我们看到了一些带有“location”和“point”名称的对象,它们分别和activity、workflow和user事件相对应。其实:
“location”指在你的工作流中活动、工作流或用户相关的事件发生时的一个指定的位置。Locations描述了要跟踪的事件。使用一个location对象,你可更精确地指定你想跟踪及排除的的事件。
跟踪points收集locations,它们能在你的工作流中的一个或多个地方触发跟踪信息。你可把跟踪点当成一个感兴趣的点来考虑。它能在你的工作流代码中跨越不同的位置。在你为跟踪点指定条件和位置后,在跟踪时它视情况可能触发也可能不触发。
我们建立一个跟踪配置文件时,真正要做的工作是把跟踪点和位置添加到profile对象中,以作为跟踪事件的过滤器去使用。如果我们不想跟踪工作流内部的活动,而只是想跟踪工作流自身的信息,那么就需要定义和创建一个新的TrackingProfile对象并为它的WorkflowTrackPoints添加数据。而ActivityTrackPoints和UserTrackPoints属性将会被留空,代码如下所示:
TrackingProfile profile = new TrackingProfile();
profile.Version = new Version("1.0.0");
WorkflowTrackPoint workflowTrackPoint = new WorkflowTrackPoint();
Array statuses = Enum.GetValues(typeof(TrackingWorkflowEvent));
foreach (TrackingWorkflowEvent status in statuses)
{
workflowTrackPoint.MatchingLocation.Events.Add(status);
}
profile.WorkflowTrackPoints.Add(workflowTrackPoint);
Windows SDK包含了一些和跟踪有关的例子、Tracking Profile Object Model这个例子提供了在代码里声明跟踪配置,然后将其以连续的XML格式输出。
在创建该配置以后,还应该在跟踪服务里更新该配置:详细青参考《WF编程》系列之44 - 承载工作流:跟踪服务 Tracking Service
SharedConnectionWorkflowCommitWorkBatchService
该服务负责处理当SQL跟踪服务和SQL持久化服务配置成使用同一个数据库时的特殊情况。在这种情况下,SharedConnectionWorkflowCommitWorkBatchService 将使用同一个数据库连接执行跟踪和持久化服务的数据查询,这样就可以使用简单的SQL事物来提交更新。它可以避免默认情况下WorkflowCommitBatchService使用System.Transaction时将引起的失误提升,也可以避免使用分布式事务协调器,已以在同一个事务里管理对两个数据库进行更新所带来的开销。
代码形式:
WorkflowRuntime workflowRuntime = new WorkflowRuntime();
workflowRuntime.AddService(new
SharedConnectionWorkflowCommitWorkBatchService(connectionString));
配置文件:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="WorkflowServiceContainer"
type="System.Workflow.Runtime.Configuration.WorkflowRuntimeSection, System.Workflow.Runtime, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</configSections>
<WorkflowServiceContainer Name="Container Name" UnloadOnIdle="true">
<CommonParameters>
<add name="ConnectionString"
value="Initial Catalog=WorkFlowStore;Data
Source=localhost;Integrated Security=SSPI;" />
</CommonParameters>
<Services> <add type="System.Workflow.Runtime.Hosting.DefaultWorkflowSchedulerService, System.Workflow.Runtime, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35"/> <add type="System.Workflow.Runtime.Hosting.SharedConnectionWorkflowTransactionService, System.Workflow.Runtime,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add type="System.Workflow.Runtime.Tracking.SqlTrackingService, System.Workflow.Runtime, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add type="System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService, System.Workflow.Runtime, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</Services>
</WorkflowServiceContainer>
<system.diagnostics>
</system.diagnostics>
</configuration>
WorkflowMonitor程序
MSDN里有一个非常好的跟踪调试程序,叫WorkflowMonitor。