C# 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()来获取回调对象后使用回调方法。

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);
        }
    }

再次运行客户端就成功啦:
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值