一个长时间运行的工作流可能有多个接收活动,如图片11.10和图片11.11所示。当第一个接收活动被调用而且一个工作流实例被创建后,所有对工作流实例的顺序调用必须向绑定信道附加一个上下文来保证正确的相关性。这意味着客户端负责跟踪它想要与之通信的工作流实例的上下文。WF使用ContextBinding元素来让上下文对客户端可见。
默认情况下,上下文在信道中对客户端可见。上下文中的相关信息是唯一定义工作流的InstanceId。客户端可以从上下文中获取InstanceId, 把它放到内存中或者写到一个本地文件中,然后把它附加到顺序调用的信道上。只要一个客户端执行初始化和顺序化调用那么这个方法就会运行的很好,客户端在调用过程中不能重启。图片11.12显示了调用顺序。
多个客户端访问同一个单一工作流实例是正常的。这些不同的客户端可能是不同的站点或者两个不同的人。在任何一种情况,对工作流进行顺序调用的客户端必须从第一个客户端获取上下文信息。
![2011041317120798.png](https://i-blog.csdnimg.cn/blog_migrate/0532cf57b064a30e80f1f67f4f5089f8.png)
图片11.12 一个客户端维护对一个工作流实例进行多次调用的上下文
为了处理多个客户端访问一个单一工作流实例的情况,上下文或者InstanceId, 必须在客户端和服务端分别存储。额外的,应该对InstanceId 使用一个友好的名字以便于客户端不必与内部生成的手工代码一起使用。在大多数商用场景中,这不是一个问题因为商用事务通常有一个确认号或者一些按顺序的独一无二的事务编号。
图片11.13显示了用来开启多个客户端来访问一个单一工作流实例的设计。在这个设计中,工作流中的接收活动显式地在一个客户端稍后可以获取到的地方存储了工作流InstanceId. 它使用一个友好的名字来存储InstanceId, 比如一个确认编号以便于客户端客户以很容易地找到它。确认编号可能已经从初始化接收活动过程中访问或者可以组装到一个URL 中。
不考虑客户端如何获取InstanceId, 它必须创建一个上下文并把它放在信道中来进行顺序调用。列表11.9 显示了执行这个操作的客户端代码。它调用GetFromSomewhere 方法来获取InstanceId然后放到代理对应的信道的上下文中。
![2011041317122387.png](https://i-blog.csdnimg.cn/blog_migrate/bcde9c020aba2a2aff2ec0d32f828eca.png)
图片11.13 多个客户端维护对一个工作流实例进行多次调用的上下文
列表11.9 将工作流上下文标识符添加到信道中的客户端代码
![2011041317124279.png](https://i-blog.csdnimg.cn/blog_migrate/9b3aa6e89b6f89e7acd4510eaa3ffae7.png)
在服务端维持工作流状态
一个长时间运行工作流的状态存储在WorkflowRuntime 类中。由于事件触发活动也在工作流中,WorkflowRuntime执行那些活动。
当一个工作流是空闲状态而且正在等待一个时间时,WorkflowRuntime 可以保持工作流状态到外部存储器来释放系统资源比如内存和CPU。更重要的是,当WorkflowRuntime关闭时,所有活跃的工作流状态必须写到外部存储器中去,否则工作流实例在运行时重新运行时将不能恢复。
WF 运行时使用一个持续性服务来保存工作流状态到外部存储器。它在工作流空闲时调用持续性服务并在运行时关闭时再次调用它。一个持续性提供者在工作流初始化之前被注册到运行时上,运行时使用服务来序列化工作流实例到外部存储器。持续性服务中没有任何关于WCF的部分,这里提及它是为了支持本例中的场景。
一个持续性服务可以使用代码或者配置文件注册到运行时。如果在一个WCF服务中自我寄宿一个工作流,宿主可以在代码中注册服务。列表11.10显示了在运行时中注册SQL持续性服务的代码。
列表11.10 使用代码添加一个持续性服务
WorkflowServiceHost serviceHost = new WorkflowServiceHost(typeof(StockService));
WorkflowPersistenceService persistenceService =
new SqlWorkflowPersistenceService(
"Initial Catalog=WFPersistence;Data Source=localhost;Integrated Security=SSPI;",
false,
new TimeSpan(1, 0, 0),
new TimeSpan(0, 0, 5));
WorkflowRuntime runtime =
serviceHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime;
runtime.AddService(persistenceService);
serviceHost.Open();
为了在一个你没有权限访问WorkflowServiceHost的地方向一个服务开启的工作流添加一个持续性服务,你需要通过配置文件定义持续性服务。这是以一个服务行为实现的。列表11.11显示了一个服务的配置文件。它与列表11.6中的类似,在行为部分添加了额外的持续性服务内容。
列表11.11 在web.config 中添加持续性服务
![2011041317134392.png](https://i-blog.csdnimg.cn/blog_migrate/d854c00398aa1b3268a3d61af8060c07.png)