zoukankan      html  css  js  c++  java
  • WCF入门四[WCF的通信模式]

    一、概述

      WCF的通信模式有三种:请求/响应模式、单向模式和双工通信。

    二、请求/响应模式

      请求/响应模式就是WCF的默认模式,前面几篇随笔中的示例都是这种模式,当客户端发送请求后(非异步状态下),即使返回的是void客户端会一直等待服务端的响应后才继续下面的操作。

      优点:可以及时的向客户端返回错误信息。

      缺点:面对服务端需要长时间处理的情况下,降低客户端的响应速度和性能。

      这个大家都好理解,就不再复述。

    三、单向模式

      单向模式和请求/响应模式相反,单向模式就是客户端发送请求后直接进行接下来的操作,不会等待服务端的响应,并且服务端也不会发送响应。所以单向模式的方法不得声明输出参数、返回值和引用参数。

      单向模式的需要在OpertaionContract中设置IsOneWay=true ,如下所示:

    [OperationContract(IsOneWay = true)]
    void ShowDay(string day);

      优点:客户端反应速度快、性能强,当然排除需要超大量传输参数的情况。

      缺点:不能及时获取服务端是否操作结果。

    四、双工通信

      双工通信就是实现客户端和服务端方法可以相互调用。一般情况下都是客户端调用服务端的方法,但是双工通信可以让服务端调用客户端的方法。双工通信时建立在上述两种方式之上的,并不是相互冲突的。

      1.服务端

      定义服务契约和回调契约,服务契约必须通过特性[ServiceContract(CallbackContract = typeof(ICustomCallback))]来关联回调契约,回调契约不必声明ServiceContract特性,但是方法必须声明OperationContract否则在客户端引用服务后无法使用该方法,这里我们用单向模式。

    namespace WcfServiceLibrary
    {
        // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IDay”。
        [ServiceContract(CallbackContract = typeof(ICustomCallback))]
        public interface IDay
        {
            [OperationContract]
            string ShowDay(int day);
        }
        public interface ICustomCallback
        {
            [OperationContract(IsOneWay=true)]
            void UserCustomMethod(string str);
        }
    }

      在配置文件中binding指定WSDualHttpBinding,支持回调的绑定有4种:WSDualHttpBinding、NetTcpBinding、NetNamedPipeBinding、NetPeerTcpBinding,我这里用第一种。

    <endpoint address="" binding="wsDualHttpBinding" contract="WcfServiceLibrary.IDay">

      实现服务契约接口,不需要实现回调契约的接口,因为回调是使用客户端的方法所以在客户端实现。OperationContext是WCF中非常重要的对象,它表示操作执行的上下文,通过OperationContext的方法GetCallbackChannel<T>()来获取回调对象后使用回调方法。

    namespace WcfServiceLibrary
    {
        // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的类名“Day”。
        public class Day : IDay
        {
            ICustomCallback customCallback = null;
            public Day()
            {
                customCallback = OperationContext.Current.GetCallbackChannel<ICustomCallback>();
            }
            public string ShowDay(int day)
            {
                customCallback.UserCustomMethod("哈哈哈哈");//使用回调方法
                return string.Format("WCF服务返回Day是:{0}", day);
            }
        }
    }

      2.客户端

      客户端引用WCF服务后会在Service References文件加下生成一个服务类,里面定义了回调接口IDayCallback如下:

        [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
        public interface IDayCallback {
            
            [System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="http://tempuri.org/IDay/UserCustomMethod")]
            void UserCustomMethod(string str);
        }

      实现回调方法,并调用WCF服务:

        class Program
        {
            static void Main(string[] args)
            {
                InstanceContext instanceContext = new InstanceContext(new CustomCallback());
                DayClient client = new DayClient(instanceContext);
                Console.WriteLine(client.ShowDay(666));
                Console.ReadLine();
            }
        }
        public class CustomCallback : IDayCallback
        {
            public void UserCustomMethod(string str) 
            {
                Console.WriteLine("这是客户端方法:{0}",str);
            }
        }

      调试可以看到,在服务端成功调用了客户端的方法UserCustomMethod(string str):

    五、回调死锁

      由于双工通信下客户端和服务端可以互相调用对方的方法,所以会出现双方都等待对方响应的情况,而造成死锁而报错。上面的例子没有造成死锁是因为使用了单向模式,不需要等待响应。那么如果需要使用带有返回值的回调方法那该怎么办呢?

      我们将上述服务端回调契约定义的回调方法改为string UserCustomMethod(string str)并去掉IsOneWay = true,然后在服务端进行以下改造:

        // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的类名“Day”。
        public class Day : IDay
        {
            ICustomCallback customCallback = null;
            public Day()
            {
                customCallback = OperationContext.Current.GetCallbackChannel<ICustomCallback>();
            }
            public string ShowDay(int day)
            {
                string str = customCallback.UserCustomMethod("哈哈哈哈");
                return string.Format("WCF服务返回Day是:{0}。{1}", day, str);
            }
        }

      之后在客户端更新服务,运行报以下错误:

     

      很明显服务不支持并发,由于等待响应而产生了死锁。可以修改ServiceBehavior特性中的ConcurrencyMode就可以了。那么我们修改下代码如下,ServiceBehavior只能声明类:

        [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
        public class Day : IDay
        {
            ICustomCallback customCallback = null;
            public Day()
            {
                customCallback = OperationContext.Current.GetCallbackChannel<ICustomCallback>();
            }
            public string ShowDay(int day)
            {
                string str = customCallback.UserCustomMethod("哈哈哈哈");
                return string.Format("WCF服务返回Day是:{0}。{1}", day, str);
            }
        }

      再次运行客户端就成功啦:

    六、说明

      这个随笔是我自己学习流程的一个记录,和大家共勉。

  • 相关阅读:
    MySql cmd下的学习笔记 —— 引擎和事务(engine,transaction)
    MySql cmd下的学习笔记 —— 有关视图的操作(algorithm)
    MySql cmd下的学习笔记 —— 有关视图的操作(建立表)
    MySql cmd下的学习笔记 —— 有关常用函数的介绍(数学函数,聚合函数等等)
    MySql cmd下的学习笔记 —— 有关多表查询的操作(多表查询练习题及union操作)
    MySql 在cmd下的学习笔记 —— 有关多表查询的操作(内连接,外连接,交叉连接)
    MySql cmd下的学习笔记 —— 有关子查询的操作(where型,from型,exists型子查询)
    MySql cmd下的学习笔记 —— 有关select的操作(order by,limit)
    剑指Offer--第21题 调整数组顺序使奇数位于偶数前面;
    剑指Offer--和为s的连续正数序列
  • 原文地址:https://www.cnblogs.com/xwc1996/p/9839840.html
Copyright © 2011-2022 走看看