本文共 4619 字,大约阅读时间需要 15 分钟。
昨天发布了《WCF服务创建与使用(请求应答模式)》,今天继续学习与强化在双工模式下WCF服务创建与使用,步骤与代码如下。
第一步,定义服务契约(Service Contract),注意ServiceContract特性上需指定回调契约
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | //服务契约 using System.ServiceModel; namespace WcfServiceLibrary1 { [ServiceContract(Namespace = "http://www.zuowenjun.cn" , CallbackContract = typeof (ICallback))] public interface IHello { [OperationContract(IsOneWay = true )] void SetName( string name); } } //回调契约(由于回调契约本质也是一个服务契约,所以定义方式和一般意义上的服务契约基本一样。 //有一点不同的是,由于定义服务契约时候已经通过[ServiceContract(CallbackContract=typeof(ICallback))]指明ICallback是一个服务契约了,所以ICallback不再需要添加ServiceContractAttribute特性) using System.ServiceModel; namespace WcfServiceLibrary1 { public interface ICallback { [OperationContract(IsOneWay = true )] void ShowHello( string name); } } |
第二步,实现服务契约,这里通过OperationContext.Current.GetCallbackChannel()获取回调契约
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | using System.ServiceModel; namespace WcfServiceLibrary1 { [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)] public class HelloService:IHello { public void SetName( string name) { ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>(); callback.ShowHello(name); } } } |
注意:ConcurrencyMode = ConcurrencyMode.Reentrant是设置并发模式,Reentrant与Multiple均可适用于多并发,默认是Single
第三步,创建服务寄宿程序,方法很多,我这里采取常用的配置方法
1.CONFIG文件配置部份:
(注: 1.在WCF预定义绑定类型中,WSDualHttpBinding和NetTcpBinding均提供了对双工通信的支持,但是两者在对双工通信的实现机制上却有本质的区别。WSDualHttpBinding是基于HTTP传输协议的;而HTTP协议本身是基于请求-回复的传输协议,基于HTTP的通道本质上都是单向的。WSDualHttpBinding实际上创建了两个通道,一个用于客户端向服务端的通信,而另一个则用于服务端到客户端的通信,从而间接地提供了双工通信的实现。而NetTcpBinding完全基于支持双工通信的TCP协议。 2.若绑定类型采用NetTcpBinding,则地址应变更为:net.tcp://127.0.0.1:10800/HelloService,且不能有behaviorConfiguration配置)
1 2 3 4 5 6 7 8 9 10 11 | <? xml version="1.0" encoding="utf-8" ?> < configuration > < system.serviceModel > < services > </ service > < service name="WcfServiceLibrary1.HelloService"> < endpoint address="http://127.0.0.1:10800/HelloService" binding="wsDualHttpBinding" contract="WcfServiceLibrary1.IHello"></ endpoint > </ service > </ services > </ system.serviceModel > </ configuration > |
2.代码部份:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | using System; using WcfServiceLibrary1; using System.ServiceModel; using System.ServiceModel.Description; namespace ConsoleApplicationHost { class Program { static void Main( string [] args) { BuildHelloServiceHostByConfig(); } static void BuildHelloServiceHostByConfig() { using (ServiceHost host = new ServiceHost( typeof (HelloService))) { host.Opened += (s, e) => { Console.WriteLine( "HelloService已经启动,按按回车键终止服务!" ); }; host.Open(); Console.ReadLine(); } } } } |
第四步,客户端程序调用WCF服务
注:在客户端程序中首先需要创建或引用WCF服务类库,然后创建实现回调契约的类
实现回调契约:
1 2 3 4 5 6 7 8 9 10 11 12 13 | using System; using WcfServiceLibrary1; namespace ConsoleApplicationClient { public class HelloCallBack:ICallback { public void ShowHello( string name) { Console.WriteLine( "Hello! {0}.欢迎光临IT文俊社区网,地址:www.zuowenjun.cn" ,name); } } } |
1.CONFIG文件配置部份:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <? xml version="1.0" encoding="utf-8" ?> < configuration > < system.serviceModel > < bindings > < wsDualHttpBinding > < binding name="HelloServiceBinding" clientBaseAddress="http://127.0.0.1:10801/HelloServiceCallback"></ binding > </ wsDualHttpBinding > </ bindings > < client > < endpoint name="HelloService" address="http://127.0.0.1:10800/HelloService" binding="wsDualHttpBinding" contract="WcfServiceLibrary1.IHello"> </ endpoint > </ client > </ system.serviceModel > </ configuration > |
2.代码部份:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | using System; using System.ServiceModel; using WcfServiceLibrary1; namespace ConsoleApplicationClient { class Program { static void Main( string [] args) { CallHelloService(); Console.WriteLine( "按任意键结束。" ); Console.Read(); } static void CallHelloService() { Console.Write( "请输入您的网名:" ); string input = Console.ReadLine(); InstanceContext instanceContext = new InstanceContext( new HelloCallBack()); using (DuplexChannelFactory<IHello> channel = new DuplexChannelFactory<IHello>(instanceContext, "HelloService" )) { IHello proxy = channel.CreateChannel(); using (proxy as IDisposable) { proxy.SetName(input); Console.ReadLine(); //注意这句需保留,目的是为了阻止调用proxy的Dispose方法,因为该方法将会试图关闭底层的TCP连接。由于服务端的回调操作也会使用该TCP连接,如果在回调操作尚未执行完毕就试图关闭网络连接,将会导致回调无法正常执行 } } } } } |
这里特别说明一下,建议在定义服务方法时,若没有返回值,建议为方法添加IsOneWay=True特性,可以使客户端不用等待请求回复,虽然设置ConcurrencyMode = ConcurrencyMode.Reentrant,但若采用WINFORM客户端使用,则会出现TIMEOUT错误,具体分析与解决方法,详见:
说明:发表这篇文章参考了如下作者的文章:
文章同步发表于我的个人网站:
本文转自 梦在旅途 博客园博客,原文链接:http://www.cnblogs.com/zuowj/p/4366939.html ,如需转载请自行联系原作者