WF事件驱动(4)

前面三篇,我介绍到了如何在WF 4中设计简单的审批流程,没有什么特别出奇的技术,只不过WF4对于事件机制有了不小的改进吧。

这一篇要来谈谈更加深入一点的话题:如果我们的流程需要长时间才能完成(这是很常见的),那么如何在这些流程空闲(例如等待经理审批)的时候,更好地管理它们呢?

我们都知道,默认情况下,所有流程实例都是在内存中被创建的一个对象。那么这里提到的管理,有两个层面的意思:

  1. 如果某些实例处于空闲状态,那么他们所占用的内存可能是浪费的。
  2. 由于可能因意外情况导致的宕机(例如停电,或者被某个恶作剧者按下了重启按钮),所以放在内存中的实例是很不保险的

所以,为了达到上面的两个目的,WF 提供了所谓的“持久化”的功能。就是支持我们将工作流实例通过一定的方式保存起来,等需要的时候再取出来即可。

WF3就开始支持这种特性,那时候称之为“持久化服务”。WF4对此做了进一步的改进和完善。本文主要就是讨论WF4下面如何做持久化。

 

完整代码,请通过 这里 下载

 

1. 准备持久化数据库

WF的持久化功能默认是用一个SQL Server的数据库来保存数据的。当然,在此基础上我们可以扩展。但通常使用默认的这个数据库是明智的选择。

WF4提供了两个脚本,可以让我们来生成这个数据库。这两个脚本通常在下面的目录

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\SQL\en

【注意】如果你不是x64的系统,则可能是C:\Windows\Microsoft.NET\Framework\v4.0.30319\SQL\en

image

我们可以手工先在SQL Server Management Studio中创建一个数据库,例如叫WF4

image

然后,将数据库上下文切换到WF4,依次运行两个脚本

SqlWorkflowInstanceStoreSchema.sql

SqlWorkflowInstanceStoreLogic.sql

 

这个数据库的结构如果有兴趣,可以研究一下。这里就不过多展开了

image

 

2. 修改宿主程序,添加持久化服务的功能

数据库准备好之后,我们需要对宿主稍做修改,就可以完成持久化功能的配置

首先,我们需要在宿主程序中添加两个程序集引用

image

修改Main方法代码如下 (请注意红色字体)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Activities;
using System.ServiceModel.Activities;
using System.ServiceModel.Description;

using System.Activities.DurableInstancing;
using System.Runtime.DurableInstancing;
using System.Activities.Persistence;
using System.ServiceModel.Activities.Description;
using System.Xml.Linq;

namespace Host
{
    class Program
    {
        static void Main(string[] args)
        {
            var host = new WorkflowServiceHost(
                new DocumentReviewLib.DocumentReviewWorkflow(),
                new Uri("http://localhost:8080/DRS"));

            host.AddDefaultEndpoints();//这个方法是添加了一些标准的端点

            host.Description.Behaviors.Add(
                new ServiceMetadataBehavior() { HttpGetEnabled = true });

            host.AddServiceEndpoint(
                "IMetadataExchange",
                MetadataExchangeBindings.CreateMexHttpBinding(),
                "mex");


            var store = new SqlWorkflowInstanceStore(
                "server=(local)\\sqlexpress;database=WF4;integrated security=true");
            
            host.DurableInstancingOptions.InstanceStore = store;

            host.Open();
            Console.WriteLine("Server is ready.");
            Console.Read();

        }
    }
}

 

这样就可以完成服务的配置了。当然,我们这里仅仅是为了直观期间,用了代码的方式(而且用的是最简单的做法)。在生产环境下,我们可能会倾向于用配置文件的方式,而不是代码。

事实上,我个人认为WCF,WF中一个很大的亮点就是减少了对代码的依赖度,确实还是做得不错的。

 

 

3. 调试程序

按下F5进行调试

image

image

我们回到数据库看一下情况,请注意看那个InstancesTable

image

也就是说,它已经把这四个实例保存到了数据库中。

 

然后,我们接下来对流程进行审批

image

很显然,236738261这个流程已经结束了,我们再来看一下数据库中的记录

image

我们看到,现在数据库中的记录数也变为了3条。

 

 

4.如何加载已经保存好的实例

既然有这样一个数据库保存好了我们的实例,那么就可以放心大胆地将宿主程序关闭掉。

我们来看,数据库中的记录仍然是在的。请注意,我因为做了其他一些测试,所以现在实例有5个

image

 

看起来很不错,不是吗?

但是有一个问题随之而来,当我们再次打开应用程序的时候,我们可能希望宿主程序能自动地加载这些实例的信息,或者说我们仍然能够对这些实例进行操作。这要如何来完成呢?

请大家按照我的步骤来做练习

4.1 将宿主程序开起来

image

4.2 将客户端开起来

image

点击“创建流程”按钮,可以多点几次

image

image

4.3 将宿主程序关闭掉

这样做的目的,是模拟一下服务器突然停电了或者类似这样的情况。

请不要将客户端关闭

4.4 重新开启宿主程序

这样做就模拟服务器重启的场景。那么,问题就是,此时客户端还能继续处理那些未完成的流程吗?

image

我们可以选择一个编号之后,还是和以前那样,点击“同意”或者“拒绝”按钮

image

我们发现,这个流程还是可以继续处理的。而且,我们并不需要在服务端做任何特殊的设计。

所以,我们可以这么总结一下:当一个流程的请求被发送到服务端,WorkflowServiceHost会收到,它先在内存中查找看是否有合适的实例,如果没有,则会尝试查看数据库中是否有合适的实例,如果有,则会加载它

 

那么,如果在内存和数据库都没有实例的话,会怎么样呢?(例如某个流程已经被处理完了,你还是硬要继续审批)。这种情况下,WorkflowServiceHost会将这个请求列为所谓的错误的消息。

为了证明这一点,我们对服务器代码稍作修改(请注意红色部分)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Activities;
using System.ServiceModel.Activities;
using System.ServiceModel.Description;

using System.Activities.DurableInstancing;
using System.Runtime.DurableInstancing;
using System.Activities.Persistence;
using System.ServiceModel.Activities.Description;
using System.Xml.Linq;

namespace Host
{
    class Program
    {
        static void Main(string[] args)
        {
            var host = new WorkflowServiceHost(
                new DocumentReviewLib.DocumentReviewWorkflow(),
                new Uri("http://localhost:8080/DRS"));

            host.AddDefaultEndpoints();//这个方法是添加了一些标准的端点

            host.Description.Behaviors.Add(
                new ServiceMetadataBehavior() { HttpGetEnabled = true });

            host.AddServiceEndpoint(
                "IMetadataExchange",
                MetadataExchangeBindings.CreateMexHttpBinding(),
                "mex");


            var store = new SqlWorkflowInstanceStore("server=(local)\\sqlexpress;database=WF4;integrated security=true");
            host.DurableInstancingOptions.InstanceStore = store;

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



            Console.WriteLine("Server is ready.");
            Console.Read();

        }


    }
}

调试的时候,可以对一个编号连续点击两次“同意”,则第二次会被视为不合法的请求。如下图所示

 

image

 

5. 如何在客户端获取待处理任务列表

在上一个练习中,我们为了测试服务器端会自动检索那些未完成的流程实例,我们将宿主程序关闭后再打开了,但是我也特别提醒大家,不要将客户端程序关闭。

为什么呢?因为如果你关闭了,那些编号就没有了,而我们UpdateTicket操作是要根据TicketId进行操作的。

那么,就引申出来一个更大的问题,客户端不可能永远开着的,那么这些未完成流程的TicketId要保存在哪里?而客户端又如何能获取到这个列表呢?

 

有的朋友可能会说,我们可以单独搞一个数据库吧,用一个表来保存这些信息好了。那当然是可以的,但并不见得是很好的一个做法。

在WF4所提供的持久化功能中,考虑到了这种问题。它可以用一个特殊的表保存我们流程运转期间的一些数据。这里姑且称为“流程数据”吧

为了实现这样的功能,需要对持久化进行必要的扩展,请大家按照我下面的步骤来操作。

5.1 创建一个PersistenceParticipant

这是所谓的持久化参与者。它将在持久化的过程中起一定的作用。

为了便于复用,我们单独创建了一个ClassLibrary,取名为Extensions

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities.Persistence;
using System.Xml.Linq;

namespace Extensions
{
    public class MyInstanceStoreParticpant : PersistenceParticipant
    {

        public int TicketId { get; set; }
        XNamespace xNS = XNamespace.Get("http://xizhang.com/DocumentReview");
       
        /// <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 = new Dictionary<XName, object>();
            readWriteValues.Add(xNS.GetName("TicketId"), this.TicketId);

            writeOnlyValues = null;
        }

    }
}

image

这里提到一个特殊的表:InstancePromotedPropertiesTable(就是在持久化那个数据库中,本例为WF4),大家如果有时间可以看一下结构。它有66个字段。

同时,在这个项目中,我们还添加一个自定义的Activity,来实现真正的数据保存

image

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;

namespace Extensions
{

    public sealed class SetTicket : CodeActivity
    {
        public InArgument<int> TicketId { get; set; }
        protected override void Execute(CodeActivityContext context)
        {
            var extension = context.GetExtension<MyInstanceStoreParticpant>();
            extension.TicketId = TicketId.Get(context);
        }
    }
}

 

5.2 在宿主中使用该扩展,并且设定要保存的信息

image

 

代码也要做相应的修改,请注意红色部分

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Activities;
using System.ServiceModel.Activities;
using System.ServiceModel.Description;

using System.Activities.DurableInstancing;
using System.Runtime.DurableInstancing;
using System.Activities.Persistence;
using System.ServiceModel.Activities.Description;
using System.Xml.Linq;

namespace Host
{
    class Program
    {
        static void Main(string[] args)
        {
            var host = new WorkflowServiceHost(
                new DocumentReviewLib.DocumentReviewWorkflow(),
                new Uri("http://localhost:8080/DRS"));

            host.AddDefaultEndpoints();//这个方法是添加了一些标准的端点

            host.Description.Behaviors.Add(
                new ServiceMetadataBehavior() { HttpGetEnabled = true });

            var store = new SqlWorkflowInstanceStore("server=(local)\\sqlexpress;database=WF4;integrated security=true");

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


            host.Description.Behaviors.Add(
                new WorkflowIdleBehavior()
                {
                    TimeToPersist = TimeSpan.FromSeconds(0)
                });

            XNamespace xNS = XNamespace.Get("http://xizhang.com/DocumentReview");
            store.Promote("DocumentReview",
                new List<XName>() { xNS.GetName("TicketId") },
                null);


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


            host.DurableInstancingOptions.InstanceStore = store;
            host.Open();



            Console.WriteLine("Server is ready.");
            Console.Read();

        }


    }
}

 

5.3 使用工作流设计,使用自定义的Activity

请确保在DocumentReviewLib中添加了如下三个引用

image

将自定义的Activity拖放咋合适位置,并且让它的属性TicketId绑定到变量

image

5.4 调试程序

启动服务器和客户端,点击多次后,到SSMS中查看 [WF4].[System.Activities.DurableInstancing].[InstancePromotedPropertiesTable]这个表的数据

image

那么,怎么查询这些数据呢?

其实也不难,我们一般推荐在数据库中做一个视图,如

USE WF4
GO

CREATE VIEW DocumentReviewTask
AS
SELECT [SurrogateInstanceId]
      ,[PromotionName]
      ,[Value1] AS TicketId
FROM [WF4].[System.Activities.DurableInstancing].[InstancePromotedPropertiesTable]

 

查询这个视图的结果如下

image

 

5.5 在宿主程序中通过一个特殊的服务,提供这个列表给客户端

因为涉及到数据访问,我们这里用一个LINQ to SQL Class来简化开发

image

从数据库中将那个视图托拽到设计器中

image

将宿主代码修改如下,请注意红色部分

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Activities;
using System.ServiceModel.Activities;
using System.ServiceModel.Description;

using System.Activities.DurableInstancing;
using System.Runtime.DurableInstancing;
using System.Activities.Persistence;
using System.ServiceModel.Activities.Description;
using System.Xml.Linq;

namespace Host
{
    class Program
    {
        static void Main(string[] args)
        {
            var host = new WorkflowServiceHost(
                new DocumentReviewLib.DocumentReviewWorkflow(),
                new Uri("http://localhost:8080/DRS"));

            host.AddDefaultEndpoints();//这个方法是添加了一些标准的端点

            host.Description.Behaviors.Add(
                new ServiceMetadataBehavior() { HttpGetEnabled = true });

            var store = new SqlWorkflowInstanceStore("server=(local)\\sqlexpress;database=WF4;integrated security=true");

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


            host.Description.Behaviors.Add(
                new WorkflowIdleBehavior()
                {
                    TimeToPersist = TimeSpan.FromSeconds(0)
                });

            XNamespace xNS = XNamespace.Get("http://xizhang.com/DocumentReview");
            store.Promote("DocumentReview",
                new List<XName>() { xNS.GetName("TicketId") },
                null);


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


            host.DurableInstancingOptions.InstanceStore = store;
            host.Open();

            var common = new ServiceHost(
                typeof(CommonService),
                new Uri("http://localhost:8080/Common"));

            common.AddServiceEndpoint(
                typeof(ICommonService).FullName,
                new BasicHttpBinding(),
                "");

            common.Open();
Console.WriteLine("Server is ready."); Console.Read(); } } [ServiceContract] public interface ICommonService { [OperationContract] int[] GetTicketIds(); } public class CommonService : ICommonService { public int[] GetTicketIds() { var ctx = new InstanceStoreDataContext(); return ctx.DocumentReviewTasks.Select(r => (int)r.TicketId).ToArray(); } } }

 

5.6 修改客户端,使用该服务

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel.Activities;
using System.ServiceModel;


namespace Client
{
    [ServiceContract]
    public interface ICommonService
    {
        [OperationContract]
        int[] GetTicketIds();
    }


    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            Load += new EventHandler(Form1_Load);
        }




        void Form1_Load(object sender, EventArgs e)
        {
            LoadTaskList();

        }

        private void LoadTaskList()
        {
            //加载所有没有完成的流程
            var factory = new ChannelFactory<ICommonService>(
                new BasicHttpBinding(), new EndpointAddress("http://localhost:8080/Common"));


            var proxy = factory.CreateChannel();

            var ids = proxy.GetTicketIds();
            foreach (var item in ids)
            {
                lstTickets.Items.Add(item);
            }
        }

        private void btCreate_Click(object sender, EventArgs e)
        {
            var proxy = new DocumentReviewClient();
            var result = proxy.CreateTicket();

            lstTickets.Items.Add(result);
        }

        private void btApproval_Click(object sender, EventArgs e)
        {
            //同意某个流程
            var action = "approval";
            UpdateTicket(action);

        }

        private void UpdateTicket(string action)
        {
            if (lstTickets.SelectedIndex > -1)
            {
                var id = int.Parse(lstTickets.SelectedItem.ToString());
                var comment = txtComment.Text;
                var proxy = new DocumentReviewClient();
                proxy.UpdateTicket(action, comment, id);

            }
        }

        private void btReject_Click(object sender, EventArgs e)
        {
            var action = "Reject";
            UpdateTicket(action);
        }

    }
}

5.7 调试程序

image

 
image
 

总结:我用了四篇文章介绍了基于WF4实现审批流程的一个例子,通过实例可以帮助大家更好地理解有关的技术。

完整代码,请通过 这里 下载

« 博主前一篇:如何让一个现有的程序集运行在Silverlight环境中
» 博主后一篇:Workflow Foundation 4.0中的事件驱动流程设计和应用(五)
« 首页前一篇:.NET中的设计模式——一步步发现装饰模式
» 首页后一篇:提高系统架构师论文成绩的总结PPT

posted on 2010-10-10 22:47 陈希章 阅读(1708) 评论(35) 编辑 收藏

评论

#1楼 2010-10-11 00:26 吉日嘎拉 不仅权限管理      

看在写文章这么辛苦的份上,也需要按推荐+1,不错,开始关注你了。
 回复 引用 查看   

#2楼 2010-10-11 08:21 sugeng      

关注  回复 引用 查看   

#3楼 2010-10-11 09:29 小庄      

楼主辛苦了,我这次还是有点建议:
1、那个WF宿主里面的东西越来越多,还是搞成配置文件好点。
2、用WF4那个数据库里面的表存储流程ID不太好吧?实际使用中是多个用户的,而且还要保存流程的状态,甚至流程启动的时候输入的标题等,这些都是和具体业务相关的,我觉得还是把这些放在单独的数据库中合适点。
 回复 引用 查看   

#4楼 211.167.64.* 2010-10-11 13:47 匿名1245的[未注册用户]

例子有错误  回复 引用   

#5楼[楼主] 2010-10-11 19:47 陈希章      

@小庄
建议不错。关于配置文件的方式,我再写了一篇。
至于业务数据,肯定是存放在单独的数据库中的,可以通过自定义Activity去实现,大多就是标准的ADO.NET操作,这里就不做展开了
 回复 引用 查看   

#6楼 139.223.23.* 2010-10-13 09:12 122222222[未注册用户]

範例有錯,可以請樓主更正一下嗎  回复 引用   

#7楼[楼主] 2010-10-13 11:35 陈希章      

@122222222
具体是什么错误
 回复 引用 查看   

#8楼 139.223.23.* 2010-10-13 16:50 122222222[未注册用户]

是EndPointNotFoundException :
沒有任何在 http://localhost:8080/Common 上進行接聽的端點可以接受該訊息。這通常是由不正確位址或 SOAP 動作所造成。若有 InnerException,可參閱以取得詳細資訊。
是不是我什麼地方沒設定好,可以幫忙解釋一下嗎?
 回复 引用   

#9楼[楼主] 2010-10-13 16:58 陈希章      

@122222222
你单独先将宿主调试,看看能不能开起来?
如果有错误,先解决宿主里面的。

正常的情况是,如果宿主开起来,也没有报任何错,同时在IE中浏览http://localhost:8080/Common,能看到一个页面的话,就表示服务已经启动了。

此时再去开客户端肯定是没有问题的

 回复 引用 查看   

#10楼 139.223.23.* 2010-10-13 17:54 122222222[未注册用户]

我發現單獨開宿主 是正常的,
但若是 用多重啟動(設定宿主&客戶端) 即使宿主優先,還是會有錯誤。
看來我的環境是:即使宿主已顯示 "Server is ready." ,服務仍是未完全啟動,還要要等個1-2秒才行。
謝謝你, 受益良多
 回复 引用   

#11楼[楼主] 2010-10-13 19:02 陈希章      

@122222222
呵呵,学会调试是很重要的。

因为我的机器比较快,所以感觉不到,直接按F5就可以了,呵呵
 回复 引用 查看   

#12楼 2010-10-17 12:51 之泪      

一直学习WF4 ,却总不知道怎么用wf4实现审批,微软提供的那个例子每台看懂,看了您的文章总算明白了,谢谢。  回复 引用 查看   

#13楼[楼主] 2010-10-17 18:20 陈希章      

@之泪
是的,我也是确实考虑到那些例子其实不易懂,所以写这个系列。希望对大家有帮助
 回复 引用 查看   

#14楼 2011-03-26 18:36 博了个客      

跪拜,太感谢您了.....希望陈老师以后还能多写些wf4.0方面的文章  回复 引用 查看   

#15楼 2011-06-22 23:32 幻想家      

这个系列非常好,辛苦了  回复 引用 查看   

#16楼 2011-07-16 09:55 mengdesen      

为什么关掉宿住 持久化没有成功呢 在clint端点击后 宿主没有反应  回复 引用 查看   

#17楼[楼主] 2011-07-16 11:16 陈希章      

@mengdesen
关掉宿主了怎么可能有用呢?
 回复 引用 查看   

#18楼 2011-07-19 08:49 mengdesen      

@陈希章
您在文章中有这样的步骤呀
4.3 将宿主程序关闭掉
这样做的目的,是模拟一下服务器突然停电了或者类似这样的情况。
4.4 重新开启宿主程序
这样做就模拟服务器重启的场景。那么,问题就是,此时客户端还能继续处理那些未完成的流程吗
我们可以选择一个编号之后,还是和以前那样,点击“同意”或者“拒绝”按钮 我们发现,这个流程还是可以继续处理的。而且,我们并不需要在服务端做任何特殊的设计。

但是我点击同意按钮 宿主程序没有反应 但是数据库中是可以看到持久化的信息的 期待楼主的回复
 回复 引用 查看   

#19楼[楼主] 2011-07-19 10:50 陈希章      

@mengdesen

关于持久化和恢复,请参考下面的文章
http://blogs.msdn.com/b/kaevans/archive/2008/12/09/understanding-persistence-in-windows-workflow-foundation.aspx
 回复 引用 查看   

#20楼 2011-07-19 14:09 mengdesen      

@陈希章
谢谢您的回复
 回复 引用 查看   

#21楼 2011-07-19 17:08 江泽      

你好,wf4.0 对Oracle持久化服务与跟踪服务是如何实现的,您能给个例子或给点思路吗?我刚接触WF4.0。谢谢!  回复 引用 查看   

#22楼[楼主] 2011-07-19 18:53 陈希章      

@江泽

你需要创建一个自定义的Instance Store,请参考下面的例子
http://msdn.microsoft.com/en-us/library/ee829481.aspx
 回复 引用 查看   

#23楼 2011-08-08 14:00 德鸿      

您好,请问您一下,这个持久化的数据库,是只能用微软的sql sever吗?用oracle可以吗?谢谢您的答复。  回复 引用 查看   

#24楼[楼主] 2011-08-08 17:37 陈希章      

@德鸿
请参考我上面的答覆,这是可以的,但是要自定义一个提供程序
 回复 引用 查看   

#25楼 2011-08-09 11:42 德鸿      

@陈希章
请教陈老师一下,那个自定义的程序大概要怎么写呢?谢谢陈老师的帮忙。
 回复 引用 查看   

#26楼 218.90.166.* 2011-08-09 16:14 wf4.0[未注册用户]

陈老师您好,执行到 3.调试程序 的时候,总是报错,“无法初始化Instancestore” 是怎么回事啊?谢谢解答  回复 引用   

#27楼[楼主] 2011-08-10 11:15 陈希章      

@wf4.0

你是不是没有准备好这个数据库呢?或者你的服务器名称和我不一样?

var store = new SqlWorkflowInstanceStore(
"server=(local)\\sqlexpress;database=WF4;integrated security=true");

host.DurableInstancingOptions.InstanceStore = store;
 回复 引用 查看   

#28楼[楼主] 2011-08-10 11:18 陈希章      

@德鸿

可以参考
http://msdn.microsoft.com/en-us/library/ee829481.aspx
要继承InstanceStore这个类型,并且实现它的一些方法
http://msdn.microsoft.com/en-us/library/system.runtime.durableinstancing.instancestore.aspx

我对Oracle谈不上熟悉,给你找了找,目前没有看到现成的Oracle方面的实现。
 回复 引用 查看   

#29楼 218.90.166.* 2011-08-10 15:05 123321jj[未注册用户]

博主您好,我出现了8楼一样的问题。然后我尝试先启动宿主,没有问题,然后在浏览器里输入 http://localhost:8080/Common,提示的页面是:“当前已禁用此服务的元数据发布。

如果具有该服务的访问权限,则可以通过完成下列步骤来修改 Web 或应用程序配置文件以便启用元数据发布:

1. 创建下列服务行为配置,或将 <serviceMetadata> 元素添加到现有服务行为配置:
。。。。。。。” 您的程序里我唯一修改的地方是我把 var store = new SqlWorkflowInstanceStore(
"server=(local)\\sqlexpress;database=WF4;integrated security=true"); 修改成了: var store = new SqlWorkflowInstanceStore(
"serverSUNRISE;database=WF4;uid=sa;pwd=jacob);

请问,我该怎么弄呢?和8楼问题一样,也是“没有终结点在侦听可以接受消息的 http://localhost:8080/Common。这通常是由于不正确的地址或者 SOAP 操作导致的。如果存在此情况,请参见 InnerException 以了解详细信息” 谢谢您的解答

posted on 2011-09-03 16:56  Mayvar  阅读(2555)  评论(1编辑  收藏  举报

导航