WF4工作流服务和双工通信

简介:

译:http://msmvps.com/blogs/theproblemsolver/archive/2010/05/03/workflow-4-services-and-duplex-communications.aspx

双工通信在很多时候都很有用,比如一个服务允许通知用户当前的进度情况。一般情况下,我们可以使用WCF来实现,你可以通过使用指定CallbackContract的ServiceContract属性的服务使用双工,如服务器端的代码如下:

[ServiceContract(CallbackContract = typeof(IService1Callback))]
public interface IService1
{
    [OperationContract]
    string GetData(int value);
}
 
[ServiceContract]
public interface IService1Callback
{
    [OperationContract]
    void Reply(string message);
}

客户端代码如下:

class Program
{
    static void Main(string[] args)
    {
        var callback = new Service1Callback();
        var proxy = new Service1Client(new InstanceContext(callback));
 
        Console.WriteLine(proxy.GetData(42));
 
        Console.ReadLine();
    }
}
 
class Service1Callback : IService1Callback
{
    public void Reply(string message)
    {
        Console.WriteLine(message);
    }
}

但是这种方式并不适用于WF4中,因为WF4中没有ServiceContract属性,不能指定CallbackContract。然而WF4支持双工通信。

代替正常WCF的双工服务,工作流服务使用一种架构被称作持久化双工,这是一种更分离的方式来实现双工通信,他的优点是通信的两端都是独立工作的,这也意味着一般的双工通信的缺点在这里不复存在。我们甚至可以在回调端使用一个完全不同于原始请求的绑定。不过作为客户端有一个缺点就是必须创建自己的ServiceHost并且做为一个完整的WCF服务,比正常的双工通信要复杂一些。下面我们看下如何实现。

duplex1

第一步创建工作流服务,这个和其他的WCF工作流服务应用程序是一样的,持久化的双工需要一个上下文绑定,所以我们首先将绑定更改为wsHttpContextBinding如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <protocolMapping>
      <add scheme="http" binding="wsHttpContextBinding" />
    </protocolMapping>
    <!-- Remainder deleted -->
  </system.serviceModel>
</configuration>
 

下一步添加一个客户端的控制台应用程序用来调用工作流服务,添加服务引用及如下代码:

static void Main(string[] args)
{
    var proxy = new ServiceClient();
    Console.WriteLine(proxy.GetData(42));
 
    Console.ReadLine();
}
 

然后我们添加双工部分,首先我们要在客户端添加一个ServiceHost暴漏一个回调契约和回调服务定义,不像正常的双工服务定义契约在服务端,我们需要在客户端定义契约,代码如下:

[ServiceContract]
interface IServiceCallback
{
    [OperationContract(IsOneWay = true)]
    void Update(string message);
}
 
[ServiceBehavior(InstanceContextMode= InstanceContextMode.Single)]
class ServiceCallback : IServiceCallback
{
    public void Update(string message)
    {
        Console.WriteLine(message);
    }
}

 

下一步宿主这个服务,代码如下:

static void Main(string[] args)
{
    var address = "http://localhost:8080/ServiceCallback";
    var serviceCallback = new ServiceCallback();
    var host = new ServiceHost(serviceCallback, new Uri(address));
 
    host.Open();
 
 
    var proxy = new ServiceClient();
    Console.WriteLine(proxy.GetData(42));
 
    Console.ReadLine();
 
    proxy.Close();
    host.Close();
}
 

 

下一步是使工作流服务调用返回给客户端。 为此,我们需要做一些的事情。 首先,我们要让工作流服务知道在哪里可以回调。 这是通过将一个 CallbackContextMessageProperty 回调地址添加到请求标头。

这可以通过使用一个 OperationContextScope 来替换proxy.GetDate() 实现,代码如下:

var proxy = new ServiceClient();
using (new OperationContextScope((IContextChannel)proxy.InnerChannel))
{
    var context = new CallbackContextMessageProperty(address, new Dictionary<string, string>());
    OperationContext.Current.OutgoingMessageProperties.Add(CallbackContextMessageProperty.Name, context);
    Console.WriteLine(proxy.GetData(42));
}
 

 

然后我们更新工作流本身,首先我们先增加一个CorrelationHandle变量表示回调关联。如下图:

duplex2

下一步在GetData Receive活动的CorrelationInitializer中初始化callbackHandle,如下图:

duplex3

下一步我们需要一个Send活动来发送响应给客户端,设置其CorrelatesWith为之前初始化的callbackHandle,如下图:

duplex4

最后我们设置Send活动属性来匹配客户端的回调服务,如下:

duplex5

注意上面的设置中我们没有设置AddressUri和EndpointAddress,因为他可以通过请求上下文和回调关联句柄来提供,我们还设置了basicHttpBinding绑定,因为这个是客户端使用的。

最后我们需要增加一个传递回来的消息,如下:

duplex6

都完成之后,我们可以运行服务端和客户端,可以得到服务端的回调在客户端上:

duplex7

如果忘记设置回调CorrelationHandle会导致客户端得不到消息,会得到一个异常“Endpoint with Name='<not specified>' and ServiceContract '<not specified>' has a null or empty Uri property. A Uri for this Endpoint must be provided.”,这是由于Send活动找不到他的回调地址导致。

不能从客户端传递空的上下文,CallbackContextMessageProperty有几个构造函数重载,一个只有一个EndpointAddress参数,没有上下文参数。看起来好像是一个很好的选择我们可以不用指定任何的上下文信息。不幸的是当Send活动尝试寻找他的回调地址的时候会导致ArgumentNullException异常,异常信息为:"Value cannot be null. Parameter name: context".

代码下载:DuplexDemo.zip

 

 

本文转自生鱼片的博客园博客,原文链接:http://www.cnblogs.com/carysun/archive/2010/05/04/WF4-Service-Duplex.html,如需转载请自行联系原作者

相关文章
|
6月前
|
网络协议 物联网 开发者
详细介绍 MQTT 的工作原理,包括 MQTT 协议的特点、核心概念以及消息传递的流程
详细介绍 MQTT 的工作原理,包括 MQTT 协议的特点、核心概念以及消息传递的流程
680 1
|
JavaScript