本文示例:
Live SkyDrive 下载:
Box 下载(其中的Nocturne_Workflow_Hosting.zip文件):
在这个例子中,我们的目标就是解决前面提到的种种问题和限制。我们实现一个自定义的工作流管理类以及一个相关的工作流实例包装类。这些类将封装很多代码,用来host或者是与工作流运行时进行交互。实现管理类之后,我们开发一个宿主控制台程序,来执行上一个例子中的测试工作流。
实现工作流实例包装
工作流管理类应该包装起来,以便于其它的工程复用。我们创建一个Empty Workflow Project工程,命名为Nocturne.Workflow.Hosting。这是强命名,我们将在以后多次用到。一个常被复用的模块应该以这种命名方式存在于我们的机器里。
添加一个普通的C#类,名为WorkflowInstanceWrapper,然后添加下面的代码。说明已经包含在注释当中。
using System;
using System.Collections.Generic;
using System.Threading;
using System.Workflow.Runtime;
namespace Nocturne.Workflow.Hosting
{
/// <summary>
/// 工作流实例的容器
/// </summary>
[Serializable]
public class WorkflowInstanceWrapper
{
private WorkflowInstance _workflowInstance;
private ManualResetEvent _waitHandle = new ManualResetEvent(false);
private Dictionary<string, object> _outputParameters = new Dictionary<string, object>();
private Exception _exception;
private string _reasonSuspended = string.Empty;
public WorkflowInstanceWrapper(WorkflowInstance instance)
{
_workflowInstance = instance;
}
#region 公开属性与方法
/// <summary>
/// 获取工作流实例的 ID
/// </summary>
public Guid Id
{
get
{
if (_workflowInstance != null)
{
return _workflowInstance.InstanceId;
}
else
{
return Guid.Empty;
}
}
}
/// <summary>
/// 输出参数的集合
/// </summary>
public Dictionary<string, object> OutputParameters
{
get { return _outputParameters; }
set { _outputParameters = value; }
}
/// <summary>
/// 一个等待句柄。宿主应用程序可以使用它,挂起
/// 进程直到工作流完成。
/// </summary>
public ManualResetEvent WaitHandle
{
get { return _waitHandle; }
set { _waitHandle = value; }
}
/// <summary>
/// 工作流可能抛出的异常对象
/// </summary>
public Exception Exception
{
get { return _exception; }
set { _exception = value; }
}
/// <summary>
/// 工作流挂起的原因
/// </summary>
public string ReasonSuspended
{
get { return _reasonSuspended; }
set { _reasonSuspended = value; }
}
/// <summary>
/// 真实的工作流实例
/// </summary>
public WorkflowInstance WorkflowInstance
{
get { return _workflowInstance; }
}
/// <summary>
/// 工作流完成的信号,宿主应用程序可以停止等待
/// </summary>
public void StopWaiting()
{
_waitHandle.Set();
}
#endregion
}
}
实现工作流管理类
接下来我们来实现工作流管理类。它的目的就在于处理与WorkflowRuntime实例的主要交互行为,并不是代替WorkflowRuntime类,常规的任务比如创建和启动工作流都由此类来处理。从这一点上来说,很像是三层程序结构模型里的“数据访问层”。
该类同样包含了WorkflowRuntime的事件处理句柄。当一个工作流完成或中断的时候,这个处理代码会在集合中找到WorkflowInstanceWrapper,设置输出参数、异常,或是挂起原因。这就可以同时保存工作流的各种结果,交由宿主程序处理。
添加一个WorkflowRuntimeManager类,代码如下:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Workflow.Runtime;
namespace Nocturne.Workflow.Hosting
{
public class WorkflowRuntimeManager : IDisposable
{
// 定义两个实例变量,_workflowRuntime变量保存着到WorkflowRuntime实例的引用
// _workflows变量是一个以Guid为键值的WorkflowInstanceWrapper的字典。
private WorkflowRuntime _workflowRuntime;
private Dictionary<Guid, WorkflowInstanceWrapper> _workflows = new Dictionary<Guid, WorkflowInstanceWrapper>();
/// <summary>
/// 构造函数。
/// </summary>
/// <param name="instance"></param>
public WorkflowRuntimeManager(WorkflowRuntime instance)
{
_workflowRuntime = instance;
if (instance == null)
{
throw new NullReferenceException("需要一个非空的 WorkflowRuntime 实例");
}
// 提交所有的工作流事件
SubscribeToEvents(instance);
}
/// <summary>
/// 创建并启动一个工作流。
/// </summary>
/// <param name="workflowType">待启动的工作流类型</param>
/// <param name="parameters">入口参数</param>
/// <returns>包装在一个WorkflowInstanceWrapper里的工作流实例</returns>
public WorkflowInstanceWrapper StartWorkflow(Type workflowType, Dictionary<string, object> parameters)
{
WorkflowInstance instance = _workflowRuntime.CreateWorkflow(workflowType, parameters);
WorkflowInstanceWrapper wrapper = AddWorkflowInstance(instance);
instance.Start();
return wrapper;
}
#region 公共属性和事件
/// <summary>
/// 获取WorkflowRuntime实例
/// </summary>
public WorkflowRuntime WorkflowRuntime
{
get { return _workflowRuntime; }
}
/// <summary>
/// 获取工作流实例包装的一个字典
/// </summary>
public Dictionary<Guid, WorkflowInstanceWrapper> Workflows
{
get { return _workflows; }
}
/// <summary>
/// 记录该类的日志信息的事件
/// </summary>
public event EventHandler<WorkflowLogEventArgs> MessageEvent;
#endregion
#region 工作流集合管理
/// <summary>
/// 从工作流字典中移除某个实例
/// </summary>
/// <param name="workflowId"></param>
public void ClearWorkflow(Guid workflowId)
{
if (_workflows.ContainsKey(workflowId))
{
_workflows.Remove(workflowId);
}
}
/// <summary>
/// 从字典中清除所有的工作流
/// </summary>
public void ClearAllWorkflows()
{
_workflows.Clear();
}
/// <summary>
/// 向字典中添加一个新的工作流实例
/// </summary>
/// <param name="instance"></param>
/// <returns></returns>
private WorkflowInstanceWrapper AddWorkflowInstance(WorkflowInstance instance)
{
WorkflowInstanceWrapper wrapper = null;
if (!_workflows.ContainsKey(instance.InstanceId))
{
wrapper = new WorkflowInstanceWrapper(instance);
_workflows.Add(wrapper.Id, wrapper);
}
return wrapper;
}
/// <summary>
/// 依据Guid查找工作流实例
/// </summary>
/// <param name="workflowId"></param>
/// <returns></returns>
public WorkflowInstanceWrapper FindWorkflowInstance(Guid workflowId)
{
WorkflowInstanceWrapper result = null;
if (_workflows.ContainsKey(workflowId))
