网络编程之WCF编程:WCF服务和客户端的建立,回调

时间:2022-09-01 08:45:14

1.概念

Windows Communication Foundation(WCF)是由微软发展的一组数据通信的应用程序开发接口,可以翻译为Windows通讯接口。它是.NET框架的一部分,由 .NET Framework 3.0 开始引入。

WCF的终结点有三个要素组成,分别是地址(Address)、绑定(Binding)和契约(Contract),简记可写成Endpoint = ABC。
 地址:地址决定了服务的位置,解决了服务寻址的问题。
 绑定:绑定实现了通信的所有细节,包括网络传输、消息编码,以及其他为实现某种功能对消息进行的相应处理。绑定的类型包括BasicHttpBinding、WsHttpBinding、NetTcpBinding等。
 契约:契约是对服务操作的抽象,也是对消息交换模式以及消息结构的定义。

 

2.契约

WCF 的基本概念是以契约(Contract) 来定义双方沟通的协议,契约必须要以接口的方式来体现,而实际的服务代码必须要由这些合约接口派生并实现。契约分成了四种: 数据契约 (Data Contract),订定双方沟通时的数据格式。服务契约 (Service Contract),订定服务的定义。操作契约 (Operation Contract),订定服务提供的方法。消息契约 (Message Contract),订定在通信期间改写消息内容的规范。

如下图,解释了契约:

网络编程之WCF编程:WCF服务和客户端的建立,回调

 

3.绑定

由于 WCF 支持了 HTTPTCP,Named Pipe,MSMQ,Peer-To-Peer TCP 等协议,而 HTTP 又分为基本 HTTP 支持 (BasicHttpBinding) 以及 WS-HTTP 支持 (WsHttpBinding),而 TCP 亦支持 NetTcpBinding,NetPeerTcpBinding 等通信方式,因此,双方必须要统一通信的协议,并且也要在编码以及格式上要有所一致。

 基本绑定(BasicHttpBinding)

对应BasicHttpBinding类,能够将WCF服务公开为传统的ASMX Web服务,是以前就的程序能够使用现在的WCF服务。在实际开发中一个WCF服务可能会给不同的程序调用,如给Java的程序调用,给Flex的程序调用等,那么采用BasicHttpBinding最合适不过了

TCP绑定(NetTcpBinding)

对应与NetTcpBinding类,TCP绑定使用TCP协议在Intranet中跨机器的通信,注意这里是Intranet而非Internet。支持多种特性,包括可靠性、事务性、安全性、以及WCF之间通信的优化。前提是要求客户端与服务端都必须使用WCF

 

4.程序设计

第一步:wcf服务端

新建一个“windows窗体程序”名称为WCFHostServer,然后添加一个“WCF服务”名称为Service1

网络编程之WCF编程:WCF服务和客户端的建立,回调

给窗体取名为FormService,然后在窗体的Load事件中编写代码启动wcf服务:NetTcpBinding方式启动wcf服务和BasicHttpBinding方式启动wcf服务

ServiceHost m_ServiceHost;


private void Form1_Load(object sender, EventArgs e)
{
//NetTcpBinding方式启动wcf服务
m_ServiceHost = new ServiceHost(typeof(Service1));//Service1是wcf服务的类名称
NetTcpBinding binding = new NetTcpBinding();
Uri baseAddress = new Uri(string.Format("net.tcp://localhost:10086/WCFHostServer/Service1"));
m_ServiceHost.AddServiceEndpoint(typeof(IService1), binding, baseAddress);
//BasicHttpBinding方式启动wcf服务
ServiceMetadataBehavior metadataBehavior;
metadataBehavior = m_ServiceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (metadataBehavior == null)
{
metadataBehavior = new ServiceMetadataBehavior();
metadataBehavior.HttpGetEnabled = true;
metadataBehavior.HttpGetUrl = new Uri(string.Format("http://localhost:10085/WCFHostServer/Service1"));
m_ServiceHost.Description.Behaviors.Add(metadataBehavior);
}
m_ServiceHost.Open();
}

在窗体的Closeing中编写服务退出代码

private void FormService_FormClosing(object sender, FormClosingEventArgs e)
{
if (m_ServiceHost != null)
{
m_ServiceHost.Close();
m_ServiceHost = null;
}
}

在 IService1.cs中增加一个方法GetSvrTime

网络编程之WCF编程:WCF服务和客户端的建立,回调

 在Service1.cs中实现接口的方法GetSvrTime,获取服务器时间

网络编程之WCF编程:WCF服务和客户端的建立,回调

 

 

第二步:WCF客户端

新建一个“windows窗体程序”命名为WCFHostClient,在Debug中运行WCFHostServer窗体(这一步很重要),然后在项目WCFHostClient中右键--》“添加服务引用”,在地址填入以BasicHttpBinding绑定方式启动wcf服务的地址http://localhost:10085/WCFHostServer/Service1,点击“前往”,然后连接上后点击“确定”,在WCFHostClient项目中就会增加一个Service References(ServiceReference1)

网络编程之WCF编程:WCF服务和客户端的建立,回调

 将窗体命名为FormClient.cs,在窗体上增加两个textbox(ip为textbox1,port为textbox2)和一个button,如下图:

网络编程之WCF编程:WCF服务和客户端的建立,回调

在button中增加wcf客户端连接wcf服务端的代码

private void button1_Click_1(object sender, EventArgs e)
{
//basicHttpBinding绑定方式的通讯 单工
Service1Client host = new ServiceReference1.Service1Client();
string htime = host.GetSvrTime();//调用GetSvrTime获取到wcf服务器上的时间
MessageBox.Show("basicHttpBinding" + "@" + htime);

//NetTcpBinding绑定方式的通讯 双工
IService1 m_Innerclient;
ChannelFactory<IService1> m_ChannelFactory;
NetTcpBinding binding = new NetTcpBinding();
Uri baseAddress = new Uri(string.Format("net.tcp://{0}:{1}/WCFHostServer/Service1",textBox1.Text, textBox2.Text));
m_ChannelFactory=new ChannelFactory<IService1>( binding, new EndpointAddress(baseAddress));
m_Innerclient = m_ChannelFactory.CreateChannel();
string htime1=m_Innerclient.GetSvrTime();//调用GetSvrTime获取到wcf服务器上的时间
MessageBox.Show("NetTcpBinding" + "@" + htime1);
}

上面的代码是客户端调用服务端提供的接口GetSvrTime来通讯的,那么服务端如果发生了一个事件想主动通知客户端,又不可能反向调用客户端提供的接口,这时候就需要使用回调的方式进行wcf通讯了,也就是说服务端定义一个回调,客户端注册这个回调,然后就可以在这个回调里等待服务端的信息通知了

 

第三步:服务端回调通知客户端信息

wcf服务端WCFHostServer步骤

1.在IService1.cs中增加一个回调接口ISvrToCliCallBack,增加方法NotifyClientMsg,设置该方法为单向,如图:

网络编程之WCF编程:WCF服务和客户端的建立,回调
 

 2.Service1.cs中在客户端调用方法GetSvrTime的时候获取ISvrToCliCallBack的实例

网络编程之WCF编程:WCF服务和客户端的建立,回调

 注意: 使用OperationContext.Current来获取当前客户端操作的实例只有在客户端调用服务端提供的接口的时候才能有效,否则为NULL

 所以OperationContext.Current.GetCallbackChannel必须在GetSvrTime里实现

3.在FormServer窗体上增加一个按钮,点击该按钮实现通知客户端的功能

网络编程之WCF编程:WCF服务和客户端的建立,回调

 在button增加下面代码

 private void button1_Click(object sender, EventArgs e)
{
Service1.userCallBack.NotifyClientMsg("服务端给客户端通知啦");
}
调用NotifyClientMsg通知客户端


wcf客户端WCFHostClient步骤:

1.在Debug目录中开启WCFHostServer.exe,客户端在ServiceReference1更新服务引用

2.在FormClient中继承接口IService1Callback,实现方法NotifyClientMsg

网络编程之WCF编程:WCF服务和客户端的建立,回调
也就是说,当服务端有信息通知的时候(点击FromServer上面的“通知客户端”按钮)客户端的这个方法就会激活


3.在FormClient_Load中使用双工绑定方式NetTcpBinding来连接wcf服务(注:不能使用单工方式basicHttpBinding)

IService1 m_Innerclient;

 网络编程之WCF编程:WCF服务和客户端的建立,回调

注意:这里要使用双工通道DuplexChannelFactory,而不是ChannelFactory

 

4.向wcf服务注册客户端操作的实例

 m_Innerclient.GetSvrTime();
这句可以放在Form_load最后,也就是连接完wcf服务之后进行


以上wcf服务端和客户端都完成了,客户端和服务端程序运行后,点击服务端窗体的“通知客户端”,客户端就会弹出窗体