1. 使用管理员权限打开VS2017

  2. 创建一个空白解决方案:

3. 创建几个基于.net  framework的类库项目和一个基于.net Framework 的控制台项目, 然后将类库项目的class1.cs文件删除, 整体如下图:

   

4. 为每个类库添加对应的类文件:

  a)         MyWCF.WCFSimpleDuplex.Interface添加两个接口, ICalculatorService和ICallBack, 其中ICalculatorService表示要启动的服务接口, 而ICallBack表示要回调客户端时, 访问的接口

  b)         ICalculatorService 代码如下:

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代码如下

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 的代码, 它就一个类:

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的处理如下:

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节点添加如下配置:

<?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代码如下:

 

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 方法, 在客户端没有任何代码调用

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中的代码, 建议单步调试看看代码的运行过程:

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. 结束

最新文章

  1. AngularJS 系列 学习笔记 目录篇
  2. 【腾讯Bugly干货分享】打造“微信小程序”组件化开发框架
  3. DOM和DHTML等,复习总结
  4. EF生成 类型“System.Data.Entity.DbContext”在未被引用的程序集中定义
  5. Bubble Sort [ASM-MIPS]
  6. RAD,V模型
  7. centos 卸载vsftpd方法
  8. ExtJS得知--------Ext.Element学习的查询方法(示例)
  9. java 守护线程
  10. 网页设计入门&lt;一&gt;
  11. BookNote: Refactoring - Improving the Design of Existing Code
  12. buaacoding_2018算法期末上机G题.地铁建设题解
  13. 基于opencv和QT的摄像头采集代码( GoQTtemplate3持续更新)
  14. Pytorch加载模型推荐的方法
  15. Zookeeper项目开发环境搭建(Eclipse\MyEclipse + Maven)
  16. Introduction of Build Tool/Maven, Gradle
  17. linux用户和组2
  18. seajs源码分析(一)---整体结构以及module.js
  19. 使用conda 对gcc进行升级 (sonicparanoid)
  20. SpringData JPA查询分页demo

热门文章

  1. NLP(三)_统计语言模型
  2. Selenium with Python 005 - 调用js操作页面元素
  3. Django进阶Model篇004 - ORM常用操作
  4. B树, B-树,B+树,和B*树的区别
  5. 【scala】集合框架
  6. Java基础学习-extends继承(成员变量,局部变量,成员方法)
  7. 剑指Offer(第二版)面试案例:树中两个节点的最低公共祖先节点
  8. 预热篇- 总结Delphi Xe4 做App的的可行性分析. ios平台的问题还需要自行学习
  9. 如何突破JAVA程序员三年的门槛
  10. 基于UDP协议编程