65.9K
CodeProject 正在变化。 阅读更多。
Home

Windows Workflow 作为 WCF 服务和工作流持久性

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.07/5 (8投票s)

2009年1月19日

CPOL

3分钟阅读

viewsIcon

60188

downloadIcon

710

工作流计算器 WCF 服务,一个长期运行工作流的示例

引言

Windows Workflow Foundation 是 .NET 3.0 和 3.5 的一项功能。在本文中,我将尝试解释如何将工作流公开 为 WCF Web 服务。

工作流的持久化也得到了详细解释。我以顺序计算器工作流服务为例。

背景

如果您是工作流新手,请参阅 MSDN 上的 链接。它解释了所有工作流活动、持久化和 序列化概念。

Using the Code

上传的 zip 文件包含 4 个项目。该解决方案包含:

  1. WorkFlowContracts: 定义了一个 ICalculator 服务合同。此合同会公开给客户端。
  2. WWFAsWCFService: 这是一个实现 ICalculator 合同的顺序计算器工作流。
  3. WorkflowService: 公开上述工作流的服务。
  4. WinformClient: 工作流服务的消费者。

要设置整个解决方案,您首先需要创建持久化数据库。为此,请使用 Microsoft 提供的持久化架构和逻辑脚本,位于以下位置:~\Windows\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL\EN

在 SQL Server 中创建一个数据库,例如 PersistanceDB。按顺序运行以下脚本:

  1. SqlPersistenceService_Schema.sql
  2. SqlPersistenceService_Logic.sql

完成此步骤后,您的持久化数据库即可用于工作流。

现在您需要设置持久化数据库的连接字符串。

打开工作流服务的 web.config 文件。在 Servicemodel 标签下,转到 ServiceBehaviour 并指定您的持久化数据库的连接。

<serviceBehaviors>
    <behavior name="WorkFlowService.Service1Behavior">
        <!-- To avoid disclosing metadata information, 
	set the value below to false and remove the metadata 
	endpoint above before deployment -->
        <serviceMetadata httpGetEnabled="true"/>
        <!-- To receive exception details in faults for debugging purposes, 
	set the value below to true.  Set to false before deployment 
	to avoid disclosing exception information -->
        <serviceDebug includeExceptionDetailInFaults="false"/>
        <workflowRuntime name="WorkflowServiceHostRuntime" 
		validateOnCreate="true" enablePerformanceCounters="true">
            <services>
               <add type="System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService,
		 System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, 
		PublicKeyToken=31bf3856ad364e35"
                     connectionString="Data Source=*******;
			Initial Catalog=*******;user id=*******; 
			password=*******;Pooling=False"
                     LoadIntervalSeconds="1" UnLoadOnIdle= "true" />
            </services>
        </workflowRuntime>
    </behavior>
</serviceBehaviors>

构建解决方案。运行 WorkflowService。确保 WinformClient 引用了工作流服务的正确 URL。这里的想法是,每次运行客户端时都使用同一个工作流实例。

当客户端首次运行时,通过调用 StartCalculator 方法创建工作流,如下所示。我将 workflowid 保存在 appsetting 中以供以后使用。

_calcChannel = new ChannelFactory<ICalculator>
		("WSHttpContextBinding_ICalculator").CreateChannel();
            _workFlowId = _calcChannel.StartCalculator();
            Configuration config = 
		ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath);
            config.AppSettings.Settings.Remove(_WORKFLOWID);
            config.AppSettings.Settings.Add(_WORKFLOWID, _workFlowId);
            config.Save();

在工作流方面,整个工作流是使用一组 ReceiveActivities 设计的,每个活动实现 ICalculator 服务合同的 OperationContract

只有 StartCalculator Receive 活动的 CreateInstance 设置为 true,即只有一个 Receive 活动可以创建工作流实例。

一旦工作流被创建,您将在持久化数据库的 InstanceState 表中看到一个条目。

假设通过调用服务的 StartCalculator() 方法,您得到了工作流 ID。

174bf47b-4c8a-40d8-8432-0ac1f38eec9a 

下次调用同一工作流实例时,将客户端按如下方式运行:

 _calcChannel = new ChannelFactory<ICalculator>
		("WSHttpContextBinding_ICalculator").CreateChannel();
            IContextManager context = 
		(_calcChannel as IClientChannel).GetProperty<IContextManager>();
            IDictionary<string, string> instanceIdContext = 
				new Dictionary<string, string>();
            instanceIdContext.Add
		("instanceId", "174bf47b-4c8a-40d8-8432-0ac1f38eec9a");
            context.SetContext(instanceIdContext);   
 label1.Text = Convert.ToString(_calcChannel.AddNumbers(10, 20));

在上面的代码中,IContextManager 对象保存工作流的上下文信息。上下文无非就是使用 StartCalculator() 方法创建的 workflowid

通过创建一个以 instanceId 为键,以 174bf47b-4c8a-40d8-8432-0ac1f38eec9a 为值的字典,您可以重新实例化数据库中持久化的同一个工作流。应用上下文并调用计算器的 AddNumbers 方法。这对于长期运行的工作流非常有用。

关于 wsHttpContextBinding

为了与工作流服务通信,服务必须使用 basicHttpbinding wsHttpBinding。如果您想实现一些安全功能,例如上下文保护(签名、加密),则应使用 wsHttpContextBinding。服务器端的 WorkflowServiceHost (托管 WorkFlow )使用此绑定与客户端通信。在我的示例中,我在 StartCalculator() 方法调用中返回 workflowid 。但是您也可以直接从通道获取上下文。如下所示。上下文仅在其中一个 Receive Activity(在我的情况下是 StartCalculator receive activity)创建工作流实例时返回。

_calcChannel = new ChannelFactory<ICalculator>
		("WSHttpContextBinding_ICalculator").CreateChannel();
           _calcChannel.StartCalculator();
            IContextManager context = 
		(_calcChannel as IClientChannel).GetProperty<IContextManager>();
            IDictionary<string, string> instanceIdContext = context.GetContext();

希望本文能帮助您对工作流服务及其持久化有一个基本的了解。

关注点

我花了很长时间才弄清楚如何调用已持久化的工作流。
IContextManager 是关键。通过应用上下文,您可以简单地调用同一个工作流实例。
现在您可以持久化工作流了。我建议您阅读有关持久化服务的内容,您可以在其中持久化服务本身的状态。

历史

  • 2009年1月19日:初次发布
© . All rights reserved.