20181102_WCF简单双工
- 使用管理员权限打开VS2017
2. 创建一个空白解决方案:
3. 创建几个基于.net framework的类库项目和一个基于.net Framework 的控制台项目, 然后将类库项目的class1.cs文件删除, 整体如下图:
4. 为每个类库添加对应的类文件:
a) MyWCF.WCFSimpleDuplex.Interface添加两个接口, ICalculatorService和ICallBack, 其中ICalculatorService表示要启动的服务接口, 而ICallBack表示要回调客户端时, 访问的接口
b) ICalculatorService 代码如下:
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 | using System.ServiceModel; namespace MyWCF.WCFSimpleDuplex.Interface { /// <summary> /// 定义协议的时候, 同时需要定义一个回调接口 /// 示例中定义服务契约的同时定义一个回调接口ICallBack /// 双工中的函数不能带返回值 /// 如果你实在想要返回值, 那么自己用out /// </summary> [ServiceContract(CallbackContract = typeof (ICallBack))] public interface ICalculatorService { /// <summary> /// 添加isoneway属性表示, 这个函数是不是返回应答信息 ; /// </summary> /// <param name="x"></param> /// <param name="y"></param> [OperationContract(IsOneWay = true )] void Plus( int x, int y); //建立了一个Icalculator服务的协议 //这个协议带有一个回调接口ICallBack //注意WCF的双工, 不能全靠配置, 在建立服务的时候, 就要开始处理了 } } |
c) ICallBack代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | using System.ServiceModel; namespace MyWCF.WCFSimpleDuplex.Interface { /// <summary> /// 不需要协议, 因为它不是一个服务契约, 它只是一个约束,这个约束由客户端实现 /// </summary> public interface ICallBack { /// <summary> /// 这里就是回调的时候完成的函数, 这个接口也要加上Isoneway=true /// </summary> /// <param name="m"></param> /// <param name="n"></param> /// <param name="result"></param> [OperationContract(IsOneWay = true )] void Show( int m, int n, int result); } //要发布一个双工协议 ,首先在服务的建立WCF服务, 服务的契约上面指定callbackContract回调的类型 //建立回调接口, 回调接口就是等下要执行的接口 } |
5. 接下来处理 MyWCF.WCFSimpleDuplex.Model 的代码, 它就一个类:
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.Runtime.Serialization; namespace MyWCF.WCFSimpleDuplex.Model { [DataContract] public class WCFUser { //[DataMember] public int Id { get ; set ; } [DataMember] public int Age { get ; set ; } [DataMember] public int Sex { get ; set ; } [DataMember] public string Name { get ; set ; } [DataMember] public string Description { get ; set ; } } public enum WCFUserSex { Famale, Male, Other } } |
6. 关于服务类MyWCF.WCFSimpleDuplex.Service的处理如下:
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 | using System.ServiceModel; using MyWCF.WCFSimpleDuplex.Interface; namespace MyWCF.WCFSimpleDuplex.Service { /// <summary> /// 对ICalculatorService的一个实现类; 实现的时候, 除了要完成自己的计算, 还要完成, 对接口的回调 /// </summary> public class CalculatorService : ICalculatorService { /// <summary> /// 完成计算,然后去回调 /// </summary> /// <param name="x"></param> /// <param name="y"></param> public void Plus( int x, int y) { int result = x + y; System.Threading.Thread.Sleep(3000); //OperationContext表示当前操作的上下文 //OperationContext.Current.GetCallbackChannel<ICallBack>();这里有点像IOC, 给你一个接口然后生成一个实例; 注意哦, 这里的ICallBack还有没有任何实现, 而这个实现是在客户端(client)处去完成的 ICallBack callBack =OperationContext.Current.GetCallbackChannel<ICallBack>(); callBack.Show(x, y, result); } } } |
7. 接下来是控制台MyWCF.WCFSimpleDuplex.ConsoleTest的代码实现, 首先是他的配置文件
a) 初始时的配置文件如下图:
b) 在configuration节点添加如下配置:
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | <? xml version="1.0" encoding="utf-8" ?> < configuration > < startup > < supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </ startup > < system.serviceModel > <!--WCF的配置文件 , WCF的配置文件一个是基于TCP的, 一个是基于http的; 可以添加多个; 如果添加多个就是下面的配置格式 --> < behaviors > < serviceBehaviors > <!--<behavior name="MathServicebehavior"> --> <!--这里配置第一个Behavior的节点--> <!-- <serviceDebug httpHelpPageEnabled="false"/> <serviceMetadata httpGetEnabled="false"/> <serviceTimeouts transactionTimeout="00:10:00"/> <serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000"/> </behavior>--> < behavior name="CalculatorServicebehavior"> <!--这里配置第二个Behavior的节点--> < serviceDebug httpHelpPageEnabled="false"/> < serviceMetadata httpGetEnabled="false"/> < serviceTimeouts transactionTimeout="00:10:00"/> < serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000"/> </ behavior > </ serviceBehaviors > </ behaviors > <!--在tcp中上面几行和http的配置都是一样的--> < bindings > < netTcpBinding > < binding name="tcpbinding"> <!--指定为tcp的协议类型--> < security mode="None"> <!--clientCredentialType="None" → 表示加密类型 protectionLevel="None" 表示安全级别--> < transport clientCredentialType="None" protectionLevel="None"/> </ security > </ binding > </ netTcpBinding > </ bindings > < services > < service name="MyWCF.WCFSimpleDuplex.Service.CalculatorService" behaviorConfiguration="CalculatorServicebehavior"> < host > <!--这里配置第一个服务的名称和服务的具体指向类--> < baseAddresses > < add baseAddress="net.tcp://localhost:9999/CalculatorService"/> <!--指定的协议为net tcp协议--> </ baseAddresses > </ host > < endpoint address="" binding="netTcpBinding" bindingConfiguration="tcpbinding" contract="MyWCF.WCFSimpleDuplex.Interface.ICalculatorService"/> < endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/> </ service > <!--<service name="MyWCF.WCFSimpleDuplex.Service.MathService" behaviorConfiguration="MathServicebehavior"> <host>--> <!--这里配置第二个服务的名称和服务的具体指向类--> <!-- <baseAddresses> <add baseAddress="net.tcp://localhost:9999/MathService"/> </baseAddresses> </host> <endpoint address="" binding="netTcpBinding" bindingConfiguration="tcpbinding" contract="MyWCF.WCFSimpleDuplex.Interface.IMathService"/> <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/> </service>--> </ services > </ system.serviceModel > </ configuration > |
c) Program代码如下:
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | using System; using System.ServiceModel; using MyWCF.WCFSimpleDuplex.Service; namespace MyWCF.WCFSimpleDuplex.ConsoleTest { class Program { static void Main( string [] args) { try { Console.WriteLine( "开始挂起服务" ); ServiceInit.Process(); } catch (Exception ex) //如果报无法注册. . ., 则说明需要管理员权限, 启动这个程序 { //服务“SOA.WCF.Service.CalculatorService”有零个应用程序(非基础结构)终结点。这可能是因为未找到应用程序的配置文件,或者在配置文件中未找到与服务名称匹配的服务元素,或者服务元素中未定义终结点。 //没有配置文件 //另一应用程序已使用 HTTP.SYS 注册了该 URL。 //端口 9999 被其它应用程序占用了, 找到并将其停止 Console.WriteLine(ex.Message); } Console.Read(); } } /// <summary> /// WCF寄宿到控制台 /// </summary> public class ServiceInit { public static void Process() { //ServiceHost →表示提供服务的主机,使用服务的类型及其指定的基址初始化 System.ServiceModel.ServiceHost 类的新实例。 Type type = typeof (CalculatorService); ServiceHost host = new ServiceHost(type); host.Opening += (s, e) => Console.WriteLine($ "{type} 准备打开" ); //已经打开事件 host.Opened += (s, e) => Console.WriteLine($ "{type} 已经正常打开" ); //开启服务; 注意当这里需要Open的时候, 会去配置文件中检查是否有配置了MathService这个类的behavior(行为) host.Open(); Console.WriteLine( "输入任何字符,就停止" ); Console.Read(); host.Close(); Console.Read(); } } } |
8. 完成以上步骤就可以启动试试看了:
9. 可以使用 cmd 命令 netstat -ano | find "9999", 查看下端口9999是否被监听
10. 双工的服务端已经处理完毕, 接下来开始处理客户端, 当然客户端首先就要对刚才的ICallBack进行实现, 这个毋容置疑的
11. 再新打开一个VS2017, 创建一个控制台测试项目:
12. 接下来不用多想, 第一件事, 添加服务引用, 第二件事实现服务端的那个ICallBack接口
a) 添加服务引用
b) 实现ICallBack接口, 注意这个类里的Show 方法, 在客户端没有任何代码调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | using System; namespace MyWCF.WCFSimpleDuplexConsoleTest.CTest { /// <summary> /// 具体实现的回调 /// </summary> public class CallBackService : MyDuplexConsoleTest.ICalculatorServiceCallback { public void Show( int m, int n, int result) { Console.WriteLine($ "回调操作展示, 这个操作发生在两秒之后:{m}+{n}={result}" ); } } } |
c) 整体client截图:
13. 然后在program中的代码, 建议单步调试看看代码的运行过程:
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; namespace MyWCF.WCFSimpleDuplexConsoleTest.CTest { class Program { static void Main( string [] args) { MyDuplexConsoleTest.CalculatorServiceClient client = null ; try { Console.WriteLine( "客户端来测试双工!~~" ); //创建一个需要回调的实例, 等会服务端进行回调的 InstanceContext context = new InstanceContext( new CallBackService()); client = new MyDuplexConsoleTest.CalculatorServiceClient(context); client.Plus(123, 234); client.Close(); } catch (Exception ex) { if (client != null ) client.Abort(); Console.WriteLine(ex.Message); } Console.Read(); } } } |
14. 结果截图
15. 结束
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· PPT革命!DeepSeek+Kimi=N小时工作5分钟完成?
· What?废柴, 还在本地部署DeepSeek吗?Are you kidding?
· DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地
· 程序员转型AI:行业分析
· 重磅发布!DeepSeek 微调秘籍揭秘,一键解锁升级版全家桶,AI 玩家必备神器!