码迷,mamicode.com
首页 > 其他好文 > 详细

WCF 双工模式

时间:2015-07-20 19:30:52      阅读:121      评论:0      收藏:0      [点我收藏+]

标签:wcf   双工   模式   回调   单向   

WCF之消息模式分为:
1、请求/答复模式
2、单向模式
3、双工模式

其中,请求/答复模式,在博文:

 WCF 入门教程一(动手新建第一个WCF程序并部署)

WCF 入门教程二

中进行了详细介绍,此处将主要介绍:单向模式与双工模式。

1、首先,先创建一个WCF应用程序:

技术分享

创建完成后,目录如下:

技术分享

2、删除IService1.cs和Serivce1.svc,或者修改名称为:CalculateService.svc与ICalculateService.cs后,显示如下:

技术分享

3、ICalculateService.cs文件内容如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfDuplexTest
{
    // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService”。
    [ServiceContract(Namespace = "http://blog.csdn.net/jiankunking",
     SessionMode = SessionMode.Required, CallbackContract = typeof(ICalculatorDuplexCallback))]
    public interface ICalculateService
    {
        [OperationContract(IsOneWay = true)]
        void GetData(string value);

        [OperationContract]
        CompositeType Clear();

        // TODO: 在此添加您的服务操作
    }

    /*我们可以看到它有一个ICalculatorDuplexCallback的接口,由于它在ServiceContract中被标记为CallbackContract = typeof(ICalculatorDuplexCallback),所以它用于客户端回调。
    * 意即,服务端可以通过此接口中的方法将数据发送给客户端,客户端只需要实现此接口,即可接收到服务端发送过来的消息。*/
    public interface ICalculatorDuplexCallback
    {
        [OperationContract(IsOneWay = true)]
        void ComplexCalculate(string result);
        [OperationContract]
        string GetComplexCalculateResult(string value);

    }

    // 使用下面示例中说明的数据协定将复合类型添加到服务操作
    [DataContract]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";

        [DataMember]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }

        [DataMember]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
    }
}

4、CalculateService.svc文件中的内容:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfDuplexTest
{
    /*ServiceContract的SessionMode
    用于Contract上的枚举, 3种:
    Allowed: 指定协定永支持会话
    Required:指定协定必须会话绑定,否则将引发异常。BasicHttpBinding不支持会话,所以当使用BasicHttpBinding的时候毕会异常;
    NotAllowed:指定协定永不支持启动会话的绑定。*/
    // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的类名“Service”。
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class CalculateService : ICalculateService
    {
        //声明一个ICalculatorDuplexCallback接口的对象
        ICalculatorDuplexCallback callback = null;
        //CalculateService类的构造方法
        public CalculateService()
        {
            //实例化一个ICalculatorDuplexCallback
            callback = OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>();
        }

        public void GetData(string value)
        {
            //服务端调用客户端的ComplexCalculate方法
            callback.ComplexCalculate(value);
        }

        public CompositeType Clear()
        {
            CompositeType composite = new CompositeType();
            composite.BoolValue = false;
            //服务端调用客户端的GetComplexCalculateResult方法
            composite.StringValue = "测试回调客户端带有返回值的方法\r\n " + callback.GetComplexCalculateResult("客户端方法:GetComplexCalculateResult");
            return composite;
        }

    }
}
5、修改Web.config的配置文件

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <!--WCF应用程序 一下services节点需要自己手动添加-->
    <services>
      <service name="WcfDuplexTest.CalculateService">
        <endpoint address="" binding="wsDualHttpBinding" contract="WcfDuplexTest.ICalculateService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8732/Design_Time_Addresses/WcfDuplexTest/CalculateService/" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点 -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
  
</configuration>
6、新建winform客户端进行测试

7、添加服务端引用:

技术分享
8、客户端代码如下:

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;
using FormTest.CalculateService;

namespace FormTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void button1_Click(object sender, EventArgs e)
        {
            // Construct InstanceContext to handle messages on callback interface
            InstanceContext instanceContext = new InstanceContext(new CallbackHandler());
            // Create a client
            CalculateService.CalculateServiceClient client = new CalculateService.CalculateServiceClient(instanceContext);

            client.GetData("客户端 传入 参数 测试 GetData");
            MessageBox.Show("GetData 调用完成!");

            //WCF 数据契约的用途
            CompositeType composite = client.Clear();
            MessageBox.Show("Clear 调用成功 \r\n" + composite.StringValue);
        }
    }


    /// <summary>
    /// 以为能找到服务端里的ICalculatorDuplexCallback接口,谁知道服务端的接口ICalculatorDuplexCallback
    /// 是ICalculateServiceCallback的形式出现在客户端的
    /// </summary>
    //修改回调回调函数的通知线程,将其改为在非UI线程中执行。
    //WCF中可以通过在客户端回调函数类中的CallbackBehaviorAttribute中控制这一行为
    //从而解决UI死锁问题
    [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
    public class CallbackHandler : CalculateService.ICalculateServiceCallback
    {
        public void ComplexCalculate(string result)
        {
            MessageBox.Show(result.ToString());
        }

        public string GetComplexCalculateResult(string result)
        {
            return result;
        }
    }
}

小注:
在WCF回调中需要注意死锁问题
1、如果WCF中暴露出来的操作,没有返回值,则可以通过就是设置回调操作
IsOneWay=true,这样回调以后立即释放服务实例,不需要等待客户端响应消息,也可以避免死锁。
2、如果WCF中暴露出来的操作,有返回值,则需要通过,修改服务的ServiceBehavior的ConcurrencyMode为Reentrant或Multiple即可。
此时,服务端的死锁问题搞定了。
下面就需要考虑客户端的死锁问题了
客户端的死锁问题,通过在客户端回调函数类中的CallbackBehaviorAttribute中控制这一行为

死锁具体分析可以参考:点击打开链接

demo代码:点击打开链接



版权声明:作者:jiankunking 出处:http://blog.csdn.net/jiankunking 本文版权归作者和CSDN共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

WCF 双工模式

标签:wcf   双工   模式   回调   单向   

原文地址:http://blog.csdn.net/jiankunking/article/details/46967553

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!