普通WCF应用程序使用SVC文件寄宿WF 4.0服务

WF4服务配置与持久化
本文介绍如何通过普通svc文件寄宿WF4工作流,并通过配置实现流程实例的持久化和流程数据保存。
http://www.cnblogs.com/MarionZheng/archive/2011/11/07/2239322.html
由于不希望使用xamlx的WF WCF服务项目而丧失WCF配置的灵活性,所以我希望能够通过普通svc来寄宿WF4活动库中定义的xaml工作流,并通过配置实现流程实例持久化和流程数据保存。
 
WF 4.0服务的构建以及持久化请先参考 陈希章 前辈的《Workflow Foundation 4.0中的事件驱动流程设计和应用》系列文章
 
通过《Workflow Foundation 4.0中的事件驱动流程设计和应用》系列的练习,我们得到了如下的WF4工作流
 
 
我的截图可能和完成练习所得到的结果稍有差异,但其他的只是一些细小的改动,
唯一需要注意的是其中的CodeActivity,我把练习中的SetTicket,换成了PromoteValue<T>。
这个主要是为了待会能够在web.config中初始化CodeActivity用的,具体的代码和配置方法下面再详细描述
流程的xaml代码如下
复制代码
<Activity mc:Ignorable="sap" x:Class="DocApprovalProcessLib.DocApprovalProcess" sap:VirtualizedContainerService.HintSize="483,1422" mva:VisualBasic.Settings="Assembly references and imported namespaces for internal implementation" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:e="clr-namespace:Extensions;assembly=Extensions" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="clr-namespace:Microsoft.VisualBasic;assembly=System" xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities" xmlns:p="http://schemas.microsoft.com/netfx/2009/xaml/servicemodel" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:s1="clr-namespace:System;assembly=System" xmlns:s2="clr-namespace:System;assembly=System.Xml" xmlns:s3="clr-namespace:System;assembly=System.Core" xmlns:s4="clr-namespace:System;assembly=System.ServiceModel" xmlns:sa="clr-namespace:System.Activities;assembly=System.Activities" xmlns:sad="clr-namespace:System.Activities.Debugger;assembly=System.Activities" xmlns:sap="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation" xmlns:scg="clr-namespace:System.Collections.Generic;assembly=System" xmlns:scg1="clr-namespace:System.Collections.Generic;assembly=System.ServiceModel" xmlns:scg2="clr-namespace:System.Collections.Generic;assembly=System.Core" xmlns:scg3="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:sd="clr-namespace:System.Data;assembly=System.Data" xmlns:sl="clr-namespace:System.Linq;assembly=System.Core" xmlns:ssa="clr-namespace:System.ServiceModel.Activities;assembly=System.ServiceModel.Activities" xmlns:ssx="clr-namespace:System.ServiceModel.XamlIntegration;assembly=System.ServiceModel" xmlns:st="clr-namespace:System.Text;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <Sequence DisplayName="文档审批流程" sad:XamlDebuggerXmlReader.FileName="e:\zhengyi\visual studio 2010\Projects\CtripSZ.WFPlatform\DocApprovalProcessLib\DocApprovalProcess.xaml" sap:VirtualizedContainerService.HintSize="443,1382">
    <Sequence.Variables>
      <Variable x:TypeArguments="x:Int64" Name="ProcessInstanceID"/>
      <Variable x:TypeArguments="p:CorrelationHandle" Name="__handle1"/>
      <Variable x:TypeArguments="p:CorrelationHandle" Name="ProcessInstanceHandle"/>
    </Sequence.Variables>
    <sap:WorkflowViewStateService.ViewState>
      <scg3:Dictionary x:TypeArguments="x:String, x:Object">
        <x:Boolean x:Key="I***panded">True</x:Boolean>
      </scg3:Dictionary>
    </sap:WorkflowViewStateService.ViewState>
    <Pick DisplayName="文档创建" sap:VirtualizedContainerService.HintSize="421,858">
      <PickBranch DisplayName="用户发起了一个新申请" sap:VirtualizedContainerService.HintSize="307,812">
        <PickBranch.Trigger>
          <p:Receive x:Name="__ReferenceID0" CanCreateInstance="True" DisplayName="收到用户的消息" sap:VirtualizedContainerService.HintSize="277,100" OperationName="CreateProcessInstance" ServiceContractName="IDocApprovalService">
            <p:Receive.CorrelationInitializers>
              <p:RequestReplyCorrelationInitializer CorrelationHandle="[__handle1]"/>
            </p:Receive.CorrelationInitializers>
          </p:Receive>
        </PickBranch.Trigger>
        <Sequence DisplayName="新申请响应" sap:VirtualizedContainerService.HintSize="277,598">
          <sap:WorkflowViewStateService.ViewState>
            <scg3:Dictionary x:TypeArguments="x:String, x:Object">
              <x:Boolean x:Key="I***panded">True</x:Boolean>
            </scg3:Dictionary>
          </sap:WorkflowViewStateService.ViewState>
          <Assign DisplayName="产生流程实例编号" sap:VirtualizedContainerService.HintSize="255,57">
            <Assign.To>
              <OutArgument x:TypeArguments="x:Int64">[ProcessInstanceID]</OutArgument>
            </Assign.To>
            <Assign.Value>
              <InArgument x:TypeArguments="x:Int64">[DateTime.Now.ToFileTimeUtc()]</InArgument>
            </Assign.Value>
          </Assign>
          <e:PromoteValue x:TypeArguments="x:Int64" ClearExistingPromotedData="False" sap:VirtualizedContainerService.HintSize="255,22" Name="ProcessInstanceID" Value="[ProcessInstanceID]"/>
          <p:InitializeCorrelation Correlation="[ProcessInstanceHandle]" sap:VirtualizedContainerService.HintSize="255,90">
            <InArgument x:TypeArguments="x:String" x:Key="Id">[ProcessInstanceID.ToString()]</InArgument>
          </p:InitializeCorrelation>
          <p:SendReply Request="{x:Reference __ReferenceID0}" DisplayName="SendReplyTo收到用户的消息" sap:VirtualizedContainerService.HintSize="255,86">
            <p:SendMessageContent DeclaredMessageType="x:Int64">
              <InArgument x:TypeArguments="x:Int64">[ProcessInstanceID]</InArgument>
            </p:SendMessageContent>
          </p:SendReply>
          <WriteLine DisplayName="输出信息" sap:VirtualizedContainerService.HintSize="255,59" Text="[String.Format(&quot;A 'DocApprovalProcess' instance ({0}) has been created.&quot;, ProcessInstanceID)]"/>
        </Sequence>
      </PickBranch>
    </Pick>
    <Pick DisplayName="文档审批" sap:VirtualizedContainerService.HintSize="421,360">
      <PickBranch DisplayName="经理审批" sap:VirtualizedContainerService.HintSize="285,314">
        <PickBranch.Variables>
          <Variable x:TypeArguments="x:String" Name="action"/>
          <Variable x:TypeArguments="x:String" Name="comment"/>
          <Variable x:TypeArguments="x:Int64" Name="approveID"/>
        </PickBranch.Variables>
        <PickBranch.Trigger>
          <p:Receive CorrelatesWith="[ProcessInstanceHandle]" DisplayName="经理审批" sap:VirtualizedContainerService.HintSize="255,100" OperationName="SupervisorApprove" ServiceContractName="IDocApprovalService">
            <p:Receive.CorrelatesOn>
              <p:XPathMessageQuery x:Key="Id">
                <p:XPathMessageQuery.Namespaces>
                  <ssx:XPathMessageContextMarkup>
                    <x:String x:Key="xgSc">http://tempuri.org/</x:String>
                  </ssx:XPathMessageContextMarkup>
                </p:XPathMessageQuery.Namespaces>sm:body()/xgSc:SupervisorApprove/xgSc:Id</p:XPathMessageQuery>
            </p:Receive.CorrelatesOn>
            <p:ReceiveParametersContent>
              <OutArgument x:TypeArguments="x:Int64" x:Key="Id">[approveID]</OutArgument>
              <OutArgument x:TypeArguments="x:String" x:Key="action">[action]</OutArgument>
              <OutArgument x:TypeArguments="x:String" x:Key="comment">[comment]</OutArgument>
            </p:ReceiveParametersContent>
          </p:Receive>
        </PickBranch.Trigger>
        <WriteLine DisplayName="打印消息" sap:VirtualizedContainerService.HintSize="255,100" Text="[String.Format(&quot;Process {0} approved. Action : {1}, Comment :{2}&quot;, ProcessInstanceID, action, comment)]"/>
      </PickBranch>
    </Pick>
  </Sequence>
</Activity>
复制代码
  1.  
1. 下面我们来解决的,是如何通过SVC文件来寄宿 WF4 的活动库项目中定义的WCF服务
 
在Extensions项目中新建一个类CustomWorkflowServiceHostFactory.cs,该类继承自WorkflowServiceHostFactory,用于在svc文件中指定用它来初始化一个WorkflowServiceHost的实例,代码如下:
复制代码
namespace Extensions

{
    public class CustomWorkflowServiceHostFactory : WorkflowServiceHostFactory
    {
        protected override WorkflowServiceHost CreateWorkflowServiceHost(Activity activity, Uri[] baseAddresses)
        {
            return base.CreateWorkflowServiceHost(activity, baseAddresses);
        }

        protected override WorkflowServiceHost CreateWorkflowServiceHost(WorkflowService service, Uri[] baseAddresses)
        {
            var host = base.CreateWorkflowServiceHost(service, baseAddresses);
            return host;
        }
    }
}
复制代码

  1. 新建一个WCF应用程序项目,添加对如下dll的引用:Extensions.dll、DocApprovalProcessLib.dll(定义了WF4 xaml工作流的活动库)、System.Activities、System.Activities.Core.Presentation、System.Activities.DurableInstancing、System.Activities.Presentation、System.ServiceModel.Activities、System.Runtime.DurableInstancing
 
在该项目中新建svc文件DocApprovalProcessService.svc,内容如下:
<%@ ServiceHost Language="C#" Debug="true" Service="DocApprovalProcessLib.DocApprovalProcess" Factory="Extensions.CustomWorkflowServiceHostFactory" %>

  1. 如此,即完成了WF4活动库在普通WCF中的寄宿,可以右击svc文件选择“在浏览器中查看”来检查

2. 接下来,我们需要对这个svc提供出来的WF4服务来进行配置,换句话说,就是要在web.config中配置出WF4持久化等相关特性。

首先,我们来回顾一下通过程序方式寄宿WF4服务和持久化的实现,我们需要通过配置来达到相同的效果

复制代码
//工作流服务寄宿




            var host = new WorkflowServiceHost(
                new DocApprovalProcessLib.DocApprovalProcess(),
                new Uri("http://localhost:8080/DAP"));

            //增加默认终结点和元数据终结点



            host.AddDefaultEndpoints();
            host.Description.Behaviors.Add(new ServiceMetadataBehavior() { HttpGetEnabled = true });
            host.AddServiceEndpoint("IMetadataExchange", MetadataExchangeBindings.CreateMexHttpBinding(), "mex");

            //增加工作流服务持久化配置



            var store = new SqlWorkflowInstanceStore("Data Source=HP580DBSZ\\DEVDBINSTANCE;Initial Catalog=WorkflowDB;Integrated Security=True;");
            host.DurableInstancingOptions.InstanceStore = store;

            //异常过滤



            host.UnknownMessageReceived += (o, e) =>
            {
                Console.WriteLine("\n" + e.Message + "\n");
            };

            //扩展流程数据存储



            host.Description.Behaviors.Add(new WorkflowIdleBehavior() { TimeToPersist = TimeSpan.FromSeconds(0) });
            XNamespace xNS = PromotionPersistenceParticipant.PromotedPropertyXNamespace;
            store.Promote("DocApprovalProcess", new List<XName> { xNS.GetName("ProcessInstanceID") }, null);
            //host.WorkflowExtensions.Add(new Extensions.InstanceStoreParticpant());



            host.WorkflowExtensions.Add(new Extensions.PromotionPersistenceParticipant());

            //启动工作流服务



            host.Open();
复制代码
  1. 3. 之前提到我们定义了不同的PromoteValue<T> CodeActivity,有一系列的类来支持在配置中初始化CodeActivity,我们同样把它们定义在Extensions项目中,依次列出:

SqlWorkflowInstanceStorePromotionBehavior,继承自ystem.ServiceModel.Activities.Description.SqlWorkflowInstanceStore,扩展WF4服务的数据库持久化行为

复制代码
namespace Extensions

{
    public class SqlWorkflowInstanceStorePromotionBehavior : SqlWorkflowInstanceStoreBehavior, IServiceBehavior
    {
        public SqlWorkflowInstanceStorePromotionBehavior(string connectionString)
            : base(connectionString)
        {
        }

        internal SqlWorkflowInstanceStorePromotionBehavior(SqlWorkflowInstanceStoreBehavior sqlWorkflowInstanceStoreBehavior)
        {
            base.ConnectionString = sqlWorkflowInstanceStoreBehavior.ConnectionString;
            base.HostLockRenewalPeriod = sqlWorkflowInstanceStoreBehavior.HostLockRenewalPeriod;
            base.InstanceCompletionAction = sqlWorkflowInstanceStoreBehavior.InstanceCompletionAction;
            base.InstanceEncodingOption = sqlWorkflowInstanceStoreBehavior.InstanceEncodingOption;
            base.InstanceLockedExceptionAction = sqlWorkflowInstanceStoreBehavior.InstanceLockedExceptionAction;
            base.RunnableInstancesDetectionPeriod = sqlWorkflowInstanceStoreBehavior.RunnableInstancesDetectionPeriod;
        }

        public SqlWorkflowInstanceStorePromotionBehavior()
        {
        }

        public new void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            if (serviceHostBase == null)
            {
                throw new ArgumentNullException("serviceHostBase");
            }

            WorkflowServiceHost workflowServiceHost = serviceHostBase as WorkflowServiceHost;

            if (workflowServiceHost != null)
            {
                workflowServiceHost.WorkflowExtensions.Add<PromotionPersistenceParticipant>(() => new PromotionPersistenceParticipant());
            }

            base.ApplyDispatchBehavior(serviceDescription, serviceHostBase);
        }

        public void Promote(string name, IEnumerable<string> promoteAsSqlVariant, IEnumerable<string> promoteAsBinary)
        {
            XNamespace xNS = PromotionPersistenceParticipant.PromotedPropertyXNamespace;
            List<XName> sqlVariantPromotions = null;
            List<XName> binaryPromotions = null;

            if (promoteAsSqlVariant != null)
            {
                sqlVariantPromotions = new List<XName>();

                foreach (string propertyName in promoteAsSqlVariant)
                {
                    sqlVariantPromotions.Add(xNS.GetName(propertyName));
                }
            }

            if (promoteAsBinary != null)
            {
                binaryPromotions = new List<XName>();

                foreach (string propertyName in promoteAsBinary)
                {
                    binaryPromotions.Add(xNS.GetName(propertyName));
                }
            }

            base.Promote(name, sqlVariantPromotions, binaryPromotions);
        }
    }
}
复制代码

 

  1. PromotionPersistenceParticipant通用自定义流程数据的工作流持久性参与者,继承自System.Activities.Persistence.PersistenceParticipant,相当于系列练习中的InstanceStoreParticpant
  1. 复制代码
    namespace Extensions
    
    {
        public class PromotionPersistenceParticipant : PersistenceParticipant
        {
            public static XNamespace PromotedPropertyXNamespace = XNamespace.Get("http://ctripsz.com/persistence/SqlWorkflowInstanceStorePromotions");
    
            Dictionary<XName, object> promotedProperties;
    
            public PromotionPersistenceParticipant()
            {
                this.promotedProperties = new Dictionary<XName, object>();
            }
    
            public void AddPromotedVariable(string variableName, object variableValue)
            {
                this.promotedProperties[PromotedPropertyXNamespace.GetName(variableName)] = variableValue;
            }
    
            public void ClearExistingPromotionData()
            {
                this.promotedProperties.Clear();
            }
    
            ///<summary>
    
    
    
            /// 这个方法会在工作流实例被持久化的时候自动调用
    
    
    
            /// 这些数据是会被保存到InstancePromotedPropertiesTable这个表的
    
    
    
            ///</summary>
    
    
    
            ///<param name="readWriteValues"></param>
    
    
    
            ///<param name="writeOnlyValues"></param>
    
    
    
            protected override void CollectValues(out IDictionary<XName, object> readWriteValues, out IDictionary<XName, object> writeOnlyValues)
            {
                readWriteValues = null;
                writeOnlyValues = this.promotedProperties;
            }
        }
    }
    复制代码

PromoteValue<T>,这个就是我们自定义的CodeActivity了,它定义了一个供持久化参与者使用的键值对

复制代码
namespace Extensions

{
    public class PromoteValue<T> : CodeActivity
    {
        public bool ClearExistingPromotedData { get; set; }

        public string Name { get; set; }

        public InArgument<T> Value { get; set; }

        ///<summary>



        /// 如果活动返回值,则从 CodeActivity派生并从 Execute 方法返回该值



        ///</summary>



        ///<param name="context"></param>



        protected override void Execute(CodeActivityContext context)
        {
            var extension = context.GetExtension<PromotionPersistenceParticipant>();

            if (extension != null && this.Name != null && this.Value != null)
            {
                if (this.ClearExistingPromotedData)
                {
                    extension.ClearExistingPromotionData();
                }

                T propertyValue = context.GetValue<T>(this.Value);
                extension.AddPromotedVariable(this.Name, propertyValue);
            }
        }
    }
}
复制代码

  1. 额外的PromoteValues,也是一个CodeActivity,相当于PromoteValue<T>的一个集合
  1. 复制代码
    namespace Extensions
    
    {
        public class PromoteValues : CodeActivity
        {
            public PromoteValues()
            {
                this.ValuesToPromote = new Dictionary<string, InArgument>();
            }
    
            public bool ClearExistingPromotedData { get; set; }
    
            public IDictionary<string, InArgument> ValuesToPromote { get; set; }
    
            ///<summary>
    
    
    
            /// 如果活动返回值,则从 CodeActivity派生并从 Execute 方法返回该值
    
    
    
            ///</summary>
    
    
    
            ///<param name="context"></param>
    
    
    
            protected override void Execute(CodeActivityContext context)
            {
                PromotionPersistenceParticipant persistenceParticipant = context.GetExtension<PromotionPersistenceParticipant>();
    
                if (persistenceParticipant != null)
                {
                    if (this.ClearExistingPromotedData)
                    {
                        persistenceParticipant.ClearExistingPromotionData();
                    }
    
                    foreach (KeyValuePair<string, InArgument> promotedProperty in ValuesToPromote)
                    {
                        string propertyName = promotedProperty.Key;
                        object propertyValue = promotedProperty.Value != null ? promotedProperty.Value.Get(context) : null;
                        persistenceParticipant.AddPromotedVariable(propertyName, propertyValue);
                    }
                }
            }
        }
    }
    复制代码

SqlWorkflowInstanceStorePromotionElement,对应SqlWorkflowInstanceStorePromotionBehavior,继承自System.ServiceModel.Activities.Configuration.SqlWorkflowInstanceStoreElement(又继承自BehaviorExtensionElement),用于支持在配置文件中配置SqlWorkflowInstanceStorePromotionBehavior服务行为扩展

复制代码
namespace Extensions.Configuration

{
    public class SqlWorkflowInstanceStorePromotionElement : SqlWorkflowInstanceStoreElement
    {
        public override Type BehaviorType
        {
            get { return typeof(SqlWorkflowInstanceStorePromotionBehavior); }
        }

        [ConfigurationProperty("promotionSets", IsDefaultCollection = false)]
        public PromotionSetsCollection PromotionSets
        {
            get
            {
                return (PromotionSetsCollection)base["promotionSets"];
            }
        }

        protected override object CreateBehavior()
        {
            SqlWorkflowInstanceStorePromotionBehavior behavior = new SqlWorkflowInstanceStorePromotionBehavior((SqlWorkflowInstanceStoreBehavior)base.CreateBehavior());

            foreach (PromotionSet promotionSet in this.PromotionSets)
            {
                List<string> sqlVariantProperties = new List<string>();
                List<string> binaryProperties = new List<string>();

                foreach (PromotedValueElement promotedValue in promotionSet)
                {
                    (promotedValue.IsSqlVariant ? sqlVariantProperties : binaryProperties).Add(promotedValue.PropertyName);
                }

                behavior.Promote(promotionSet.Name, sqlVariantProperties, binaryProperties);
            }

            return behavior;
        }
    }
}
复制代码

  1. PromotionSetsCollection,SqlWorkflowInstanceStorePromotionElement的子配置项,表现到配置文件是一个XML集合节点
复制代码
namespace Extensions.Configuration

{
    public class PromotionSetsCollection : ConfigurationElementCollection
    {
        public override ConfigurationElementCollectionType CollectionType
        {
            get
            {
                return ConfigurationElementCollectionType.BasicMap;
            }
        }



        protected override string ElementName
        {
            get
            {
                return "promotionSet";
            }
        }

        protected override ConfigurationElement CreateNewElement()
        {
            return new PromotionSet();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((PromotionSet)element).Name;
        }
    }
}
复制代码
  1. PromotionSet,PromotionSetsCollection的子配置项,用于在配置文件中初始化一个PromoteValue<T> CodeActivity
复制代码
namespace Extensions.Configuration

{
    public class PromotionSet : ConfigurationElementCollection
    {
        public override ConfigurationElementCollectionType CollectionType
        {
            get
            {
                return ConfigurationElementCollectionType.BasicMap;
            }
        }

        [ConfigurationProperty("name", IsKey = true, IsRequired = true)]
        public string Name
        {
            get
            {
                return (string)base["name"];
            }
            set
            {
                base["name"] = value;
            }
        }

        protected override string ElementName
        {
            get
            {
                return "promotedValue";
            }
        }

        protected override ConfigurationElement CreateNewElement()
        {
            return new PromotedValueElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((PromotedValueElement)element).PropertyName;
        }
    }
}
复制代码

  1. PromotedValueElement,初始化PromoteValue<T> CodeActivity的属性
复制代码
namespace Extensions.Configuration

{
    public class PromotedValueElement : ConfigurationElement
    {
        public PromotedValueElement()
        {
        }

        [ConfigurationProperty("isSqlVariant", IsKey = false, DefaultValue = true)]
        public bool IsSqlVariant
        {
            get
            {
                return (bool)this["isSqlVariant"];
            }
            set
            {
                this["isSqlVariant"] = value;
            }
        }

        [ConfigurationProperty("propertyName", IsRequired = true, IsKey = true)]
        public string PropertyName
        {
            get
            {
                return (string)this["propertyName"];
            }
            set
            {
                this["propertyName"] = value;
            }
        }
    }
}
复制代码

  1. 4. 好了,定义了一堆WCF服务行为扩展,和WCF配置元素后,让我们在WCF项目的web.config中来使用它们

先在<system.serviceModel>节点下添加sqlWorkflowInstanceStorePromotion扩展WF持久化参与者

  1.   
    <extensions>
    
          <behaviorExtensions>
            <add name="sqlWorkflowInstanceStorePromotion" type="Extensions.Configuration.SqlWorkflowInstanceStorePromotionElement, Extensions"/>
          </behaviorExtensions>
        </extensions>

然后在<system.serviceModel>节点下配置WCf服务行为,设置workflowIdle和sqlWorkflowInstanceStorePromotion

  1.  
  2.    
    复制代码
    <behaviors>
    
          <serviceBehaviors>
            <behavior name="">
              <serviceMetadata httpGetEnabled="true"/>
              <serviceDebug includeExceptionDetailInFaults="false"/>
            </behavior>
            <behavior name="WorkflowBehavior">
              <serviceMetadata httpGetEnabled="true"/>
              <serviceDebug includeExceptionDetailInFaults="false"/>
              <workflowIdle timeToPersist="0" timeToUnload="0"/>
                        <sqlWorkflowInstanceStorePromotion
                connectionStringName="WorkflowDB"
                hostLockRenewalPeriod="00:00:05"
                runnableInstancesDetectionPeriod="00:00:02"
                instanceCompletionAction="DeleteAll"
                instanceLockedExceptionAction="AggressiveRetry"
                instanceEncodingOption="GZip">
                <promotionSets>
                  <promotionSet name="DocApprovalProcess">
                    <promotedValue propertyName="ProcessInstanceID"/>
                  </promotionSet>
                </promotionSets>
              </sqlWorkflowInstanceStorePromotion>
            </behavior>
          </serviceBehaviors>
        </behaviors>
    复制代码

最后在<system.serviceModel>下配置WCF服务终结点,这儿请一定注意,service的name必须和活动库项目中xaml文件的名称一致,例如,我的代码中是DocApprovalProcess.xaml,这儿就必须配置为DocApprovalProcess;而服务契约contract,是在xaml工作流设计中Receive活动中定义的契约名

  1.   
    复制代码
    <services>
    
          <service behaviorConfiguration="WorkflowBehavior" name="DocApprovalProcess">
            <endpoint address="" binding="wsHttpContextBinding" bindingConfiguration="" contract="IDocApprovalService"/>
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
          </service>
        </services>
    复制代码

当然,别忘记配置一个数据库连接供sqlWorkflowInstanceStorePromotion使用,你也可以在sqlWorkflowInstanceStorePromotion中改用connectionString属性直接将数据库连接字符串写到里面,而不是使用connectionStringName属性

<connectionStrings>

    <add name="WorkflowDB" connectionString="Data Source=HP580DBSZ\DEVDBINSTANCE;Initial Catalog=WorkflowDB;Integrated Security=True;Async=true;" providerName="System.Data.SqlClient"/>
</connectionStrings>
  1. 5. OK,我们已经完成了所有的工作,现在到客户端中添加指向svc的服务引用,执行一下,看看客户端和数据库是否都产生了我们预期的结果吧。

WCF客户端配置

复制代码
<system.serviceModel>

        <bindings>
            <basicHttpBinding>
                <wsHttpBinding>
                <binding name="WSHttpBinding_ICommonWorkflowService" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                    allowCookies="false">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="false"/>
                    <security mode="Message">
                        <transport clientCredentialType="Windows" proxyCredentialType="None"
                            realm=""/>
                        <message clientCredentialType="Windows" negotiateServiceCredential="true"
                            algorithmSuite="Default"/>
                    </security>
                </binding>
            </wsHttpBinding>
            <wsHttpContextBinding>
                <binding name="WSHttpContextBinding_IDocApprovalService" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                    allowCookies="false" contextProtectionLevel="Sign">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="false"/>
                    <security mode="Message">
                        <transport clientCredentialType="Windows" proxyCredentialType="None"
                            realm=""/>
                        <message clientCredentialType="Windows" negotiateServiceCredential="true"
                            algorithmSuite="Default"/>
                    </security>
                </binding>
            </wsHttpContextBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:4292/CommonWorkflowService.svc"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ICommonWorkflowService"
                contract="CommonWorkflowService.ICommonWorkflowService" name="WSHttpBinding_ICommonWorkflowService">
                <identity>
                    <userPrincipalName value="xxxxx"/>
                </identity>
            </endpoint>
            <endpoint address="http://localhost:4292/DocApprovalProcessService.svc"
                binding="wsHttpContextBinding" bindingConfiguration="WSHttpContextBinding_IDocApprovalService"
                contract="DocApprovalProcessService.IDocApprovalService" name="WSHttpContextBinding_IDocApprovalService">
                <identity>
                    <userPrincipalName value="xxxxx"/>
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
复制代码

  1. 运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值