1.WorkflowRuntime在ASP.NET下的寄宿方式
WF在APS.NET的运行方案中最直接的宿主方式,便是将workflowRuntime的起始及结束交给网站静态的Global.asax程序区块负责,将workflowRuntime.StartRuntime()置于Application_Start中执行。
Global.asax源代码如下
PS:2011-6-8
上述的这种寄宿方式保证了WorkflowRuntime在整个程序运行期间只有一个实例(Making sure Workflow Runtime has a single instance in the WebApplication Runtime)
另外一种保证“WorkflowRuntime单一实例”的方法是通过工程模式来创建WorkflowRuntime实例。
我们定义一个静态类WorkflowFactory,其代码如下:
private static object _syncRoot = new object();
//启动workflow运行时
public static WorkflowRuntime GetWorkflowRuntime()
{
//多线程环境下防止并发访问
lock (_syncRoot)
{
if (null == _workflowRuntime)
{
AppDomain.CurrentDomain.ProcessExit += new EventHandler(StopWorkflowRuntime);
AppDomain.CurrentDomain.DomainUnload += new EventHandler(StopWorkflowRuntime);
_workflowRuntime = new WorkflowRuntime();
_workflowRuntime.StartRuntime();
}
}
return _workflowRuntime;
}
//停止workflow运行时
static void StopWorkflowRuntime(object sender, EventArgs e)
{
if (_workflowRuntime != null)
{
if (_workflowRuntime.IsStarted)
{
try
{
_workflowRuntime.StopRuntime();
}
catch (ObjectDisposedException)
{
}
}
}
}
}
}
在程序中创建WorkflowRuntime实例的方法如下代码所示:
2.WorkflowRuntime服务注册
WorkflowRuntime.AddService 方法用于将指定的服务添加到工作流运行时引擎中。通过添加核心服务可以配置工作流运行时引擎。 核心服务是派生自以下任一服务基类的服务:WorkflowSchedulerService 类、WorkflowCommitWorkBatchService类、WorkflowPersistenceService 类和 TrackingService 类。 只能在工作流运行时引擎不运行的情况下添加核心服务,即当 IsStarted 为 false 时才能添加核心服务(在workflowRuntime.StartRuntime();前)。WorkflowRuntime 也可以用作存储其他服务的容器,其他工作流或宿主上运行的应用程序可能会使用这些服务。 如果您在工作流运行时引擎启动后添加派生自WorkflowRuntimeService 类的非核心服务,则 AddService 将会调用该服务实现的 Start 方法(即AddService方法会自动将添加的服务启动)。
前面的核心服务类都是派生自WorkflowRuntimeService 类,它的继承层次结构如下所示:
System.Object
System.Workflow.Runtime.Hosting.WorkflowRuntimeService
System.Workflow.Activities.ExternalDataExchangeService
System.Workflow.Runtime.Hosting.ChannelManagerService
System.Workflow.Runtime.Hosting.WorkflowCommitWorkBatchService
System.Workflow.Runtime.Hosting.WorkflowLoaderService
System.Workflow.Runtime.Hosting.WorkflowPersistenceService
System.Workflow.Runtime.Hosting.WorkflowSchedulerService
System.Workflow.Runtime.Tracking.TrackingService
从上面的基层结构我们也可以看出,WorkflowRuntimeService的7个派生服务中,只有4个是核心服务,其他的都不是核心服务。前面提到只能在workflowRuntime.StartRuntime();前添加核心服务,那么这个核心服务是如何添加的。这就涉及到了WF服务注册的问题,是通过web.config配置文件完成添加核心服务的。
web.config示例代码(摘取关键部分):
第一个WF服务注册中的内容表示增加一个叫做WorkflowRuntime的节点,在应用程序中WorkflowRuntime对象就是通过这个配置节点来创建的。
第二个WF服务注册中的内容表示节点WorkflowRuntime的名字叫做WorkflowServiceContainer,在其中添加了ManualWorkflowSchedulerService(继承自服务基类WorkflowSchedulerService)和DefaultWorkflowCommitWorkBatchService(继承自服务基类WorkflowCommitWorkBatchService)这两个核心服务,而且核心服务也必须在这里添加。
3.工作流调用及加载服务的方法
常见的方式是通过一个 StartWorkflow()方法,方法如下:
//创建本地通信服务
ExternalDataExchangeService dataService = new ExternalDataExchangeService();
//本地通信服务添加到工作流运行时WorkflowRuntime中
wr.AddService(dataService);
//GetService<T>() 从工作流运行时引擎中检索指定泛型类型的服务。
ProgressService progressService = wr.GetService<ProgressService>();
//如果在工作流运行时中检索到的ProgressService为空,则创建该服务,
//并将其添加到本地通信服务dataService中,这样,以后就能够从workflowruntime中检索到。
if (progressService == null)
{
progressService = new ProgressService();
dataService.AddService(progressService);
}
//载入WorkflowCompleted的事件驱动程序
wr.WorkflowCompleted += new EventHandler<WorkflowCompletedEventArgs>(workflowRuntime_WorkflowCompleted);
//创建工作流实例。CreateWorkflow(Type) 使用指定工作流 Type 创建新的工作流实例。
WorkflowInstance workflowInstance = wr.CreateWorkflow(typeof(WorkflowLibrary1.Workflow1));
//开始执行工作流实例。
workflowInstance.Start();
//RunWorkflow(Guid workflowInstanceId) 运行指定的工作流实例。
scheduler.RunWorkflow(workflowInstance.InstanceId);
}
解析上述程序,我们会发现可以通过GetService<T>()方法从工作流运行时引擎中检索指定泛型类型(ManualWorkflowSchedulerService)的服务。
而不能通过该方法获取ExternalDataExchangeService的服务,这是因为我们没有在web.config中为ExternalDataExchangeService服务进行注册。因为ExternalDataExchangeService不是核心服务,因此我们可以在WorkflowRuntime运行以后再添加。如上述代码所示,我们手工添加ExternalDataExchangeService服务的方法如下代码所示:
4.添加ExternalDataExchangeService服务的方法
如果要添加ExternalDataExchangeService服务,只需要在web.config中添加ExternalDataExchangeService的声明。
修改web.config以后我们需要注释掉前面手工添加ExternalDataExchangeService服务的代码才能运行,不然会报错:"异常详细信息: System.InvalidOperationException: 无法多次添加同一服务"。其他服务的添加方法都非常相似。