持久化参与者可以参与由应用程序主机触发的持久化操作(保存或加载)。 .NET Framework 4.6.1 附带两个抽象类 :PersistenceParticipant 和 PersistenceIOParticipant,可用于创建持久性参与者。 持久性参与者派生自这些类之一,它实现所需的方法,然后将该类的实例添加到 WorkflowExtensions 上的 WorkflowServiceHost 集合。 应用程序主机在保留工作流实例时可能会查找此类工作流扩展,并在适当时间对持久性参与者调用适当的方法。
以下列表描述了持久化子系统在持久化(保存)操作的不同阶段执行的任务。 持久性参与者用在第三和第四个阶段。 如果参与者是 I/O 参与者(还参与 I/O 操作的持久性参与者),则该参与者还将在第六个阶段中使用。
收集内置值,包括工作流状态、书签、映射变量和时间戳。
收集添加到与工作流实例关联的扩展集合中的所有持久性参与者。
调用由所有持久性参与者实现的 CollectValues 方法。
调用由所有持久性参与者实现的 MapValues 方法。
将工作流持久保存或保存到持久性存储中。
对所有持久性 I/O 参与者调用BeginOnSave方法。 如果参与者不是 I/O 参与者,则跳过此任务。 如果持久性段是事务性的,则在 Transaction.Current 属性中提供事务。
等待所有持久性参与者完成。 如果所有参与者在持久保存实例数据时都成功,则提交事务。
持久性参与者派生自 PersistenceParticipant 类,并且可以实现 CollectValues 和 MapValues 方法。 持久性 I/O 参与者派生自 PersistenceIOParticipant 类,除了实现 CollectValues 和 MapValues 方法外,还可以实现 BeginOnSave 方法。
每个阶段在下一阶段开始之前完成。 例如,从第一个阶段中的所有持久性参与者收集值。 然后,第一阶段中收集的所有值都提供给第二阶段中的所有持久性参与者进行映射。 然后,第一阶段和第二阶段中收集和映射的所有值都提供给第三阶段的持久性提供程序,依此等。
以下列表描述了持久性子系统在加载作的不同阶段执行的任务。 持久性参与者用在第四个阶段中。 持久性 I/O 参与者(还参与 I/O 操作的持久性参与者)还在第三个阶段中使用。
收集添加到与工作流实例关联的扩展集合中的所有持久性参与者。
从持久性存储加载工作流。
对所有持久性 I/O 参与者调用 BeginOnLoad,并等待所有持久性参与者完成。 如果持久性段是事务性的,则在 Transaction.Current 中提供事务。
根据从持久性存储中检索到的数据,在内存中加载工作流实例。
对每个持久性参与者调用 PublishValues。
持久性参与者派生自 PersistenceParticipant 类,并可能实现 PublishValues 方法。 持久性 I/O 参与者派生自 PersistenceIOParticipant 类,除了实现 PublishValues 方法外,还可以实现 BeginOnLoad 方法。
加载工作流实例时,持久性提供程序在该实例上创建锁。 这样可以防止在多节点方案中由多个主机加载实例。 如果尝试加载已锁定的工作流实例,将看到如下异常:异常“System.ServiceModel.Persistence.InstanceLockException:请求的作无法完成,因为无法获取实例'000000000-0000-0000-0000-000000000000'' 的锁”。 发生以下情况之一时,会导致此错误:
在多节点方案中,实例由另一个主机加载。 有几种不同的方法可以解决这些类型的冲突:转移对拥有锁和重试的节点的处理,或者强制将导致其他主机无法保存其工作的负载。
在单节点方案中,主机崩溃。 当主机再次启动(进程回收或创建新的持久性提供程序工厂)时,新主机会尝试加载仍被旧主机锁定的实例,因为该锁尚未过期。
在单节点方案中,问题实例在某个时间点中止,并创建了具有不同主机 ID 的新持久性提供程序实例。
锁超时值默认值为 5 分钟,可以在调用 Load时指定不同的超时值。