先来了解一下基本WCF术语
第一创建WCF服务协定
消息
消息是一个独立的数据单元,它可能由几个部分组成,包括消息正文和消息头。
服务
服务是一个构造,它公开一个或多个终结点,其中每个终结点都公开一个或多个服务操作。
终结点
终结点是用来发送或接收消息(或执行这两种操作)的构造,终结点包括一个定义消息可以发送到的目的地的位置(地址)、一个描述消息应该如何发送的通信机制规范(绑定)以及对于可以在该位置发送或者接收(或两者皆可)的一组消息的定义(服务协定),——该定义还描述了可以发送何种消息。
WCF服务作为一个终结点集合向外界公开。
类或接口都可以定义服务协定,建议使用接口,因为接口可以直接对服务协定建模
服务协定接口具有托管接口的所有优点:
--服务协定接口可以扩展任何数量的其他服务协定接口。
--一个类可以通过实现服务协定接口来实现任意数量的服务协定。
--可以通过更改接口实现来修改服务协定的实现,而让服务协定保持不变。
--可以通过实现旧接口和新接口来确定服务的版本。老客户端连接到原始版本,而信客户端则可以连接到较新的版本。
定义服务协定
在类或接口上使用ServiceContractAttribute属性标记
定义服务操作
在方法上使用OperationContractAttribute属性对其进行标记
参数和返回值
--每个操作都有一个返回值和一个参数,即使他们为void,可以使用局部方法将对对象的引用从一个对象传递到另一个对象,但与局部方法不同的是,服务操作不会传递对对象的引用。他们传递的只是对象的副本。
--这一点很重要,只是因为参数或返回值中使用的每个类型都必须是可序列化的,换言之,该类型的对象必须能够转换为字节流,并能够从字节流转换为对象。
--默认情况下,基元类型是可序列化的,.Net FrameWork 中的很多类型都是可序列化的。
服务操作的消息模式
请求/答复模式
--通过请求/答复模式,请求发送发(客户端应用程序)将接收与请求相关的答复,这是默认的模式,因为它既支持传入操作(一个或多个参数传递到该操作中),也支持返回操作(该操作将一个或多个输出值传回给调用方)
--请注意,除非指定其他基础消息模式,否则,即使服务操作返回void(在Visual Basic中为Nothing),也属于请求/答复消息交换。
--操作的结果是:除非客户端异步调用操作,否则客户端将停止处理,直到收到退出消息,即使消息正常情况下为空时也是如此。
--缺点:如果执行操作需要很长的时间,则会降低客户端性能和响应力
--优点:响应消息中可返回SOAP错误,这表名可能在通信或处理中发生了一些与服务有关的错误状况
单向模式
如果WCF服务应用程序的客户端不必等待操作完成,并且不处理SOAP错误,则该操作可以指定单向消息模式。
单向操作是可俄护短调用操作并在WCF将消息写入网络后继续进行处理的操作,通常这意味着,除非在出战消息中发送的数据极其庞大,否则客户端几乎立即继续运行(除非发送数据时出错)。此种类型的消息交换模式支持从客户端到服务应用程序的类似于事件的行为。
若要为返回Void的操作指定单向消息交换,请将IsOneWay属性设置为true,默认为false.
此方法与前面的请求/答复示例相同,单思,将IsOneWay属性设置为true意味着尽管方法相同,服务操作也不会发送返回消息,而客户端将在出站消息抵达通道层时立即返回
双工模式
--双工模式的特点是,无论使用单向消息发送还是请求/答复消息发送方式,服务和客户端均能均能够独立的向对方发送消息。对于必须直接与客户端通信或向消息交换的任意一方提供异步体验(包括类似于事件的行为)的服务来说,这种双向通信形式非常有用
--由于存在与客户但通信的附加机制,双向模式比请求/答复或单向模式要略为复杂
--若要设计双工协定,还必须设计回调协定,并将该会掉协定的类型分配给标记服务协定的ServiceContractAttribute属性(Attribute)的CallBackContract属性(prpperty).
--若要实现双工模式,您必须创建第二个接口,该接口包含在客户端调用的方法声明
创建数据协定
面向服务的应用程序(例如Windows Commnuication Foundation(WCF)应用程序)设计为与Microsoft平台和非Microsoft平台上的最大可能数量的客户端应用程序进行互操作。
为了获得最大可能的互操作性,建议您使用DataContractAttribute和DataMemberAttribute属性对您的类型进行标记,以创建数据协定。
数据协定是服务协定的一部分,用于描述您的服务操作交换的数据。
数据协定是可选的样式协定,除非您是显式应用数据协定属性,否则不会协力恶化任何类型或数据成员
数据协定与托管代码的访问范围无关,可以对私有数据成员进行序列化,并将其发送到其他位置,以便可以公开访问它们
WCF处理用启用操作功能的基础SOAP消息的定义,并处理数据类型到消息正文的序列化和从消息正文进行反序列化,数据类型一旦序列化,您就无需在设计操作时考虑基础消息交换基础结构
可以使用其他序列化机制,标准Iserializable,SerializableAttribute和IXmlSerializable机制都可用于处理数据类型到基础SOAP消息序列化,这些消息可讲数据类型从一个应用程序带到另一个应用程序
下面我们通过实例代码来详细了解一下三种模式
第一种请求/答复模式与上一节中的实例完全一样的,通常默认的都是请求/答复模式,在此略过。
第二种单向模式
单向模式只需要在请求/答复模式上稍加改动即可。
[OperationContract(IsOneWay=true)]
void TestMethod(string strInput);
在接口定义方法加上IsOneWay=true,即表示客户端调用的该方法为单向模式,IsOneWay在默认的情况下值为false的。
在接口实现上就没什么区别了。
public void TestMethod(string strInput)
{
System.Threading.Thread.Sleep(10000);
}
我们在实现让此方法暂停10秒钟,那么如果是正常的请求/答复模式调用此方法,会在10秒钟之后客户端才能有相应的响应。而现在的单向模式,虽然在服务实现添加暂停10秒的时间,但是客户端只要调用该服务方法后,不会有服务端的响应,可以继续请求或操作客户端其他的操作。
第三种双工模式
首先创建服务接口和客户端回调接口
[ServiceContract(CallbackContract=(typeof(IClientCallBack)))]
public interface ICalculatorService
{
[OperationContract(IsOneWay=true)]
void Test(double x,double y);
}
public interface IClientCallBack
{
[OperationContract(IsOneWay=true)]
void ClientTest();
}
双工服务需要在服务接口属性中添加回调协定的类型
public class CalculatorService : ICalculatorService
{
public void Test(double x, double y)
{
double result = x + y;
IClientCallBack CallBack = OperationContext.Current.GetCallbackChannel<IClientCallBack>();
CallBack.ClientTest(x, y, result);
}
}
OperationContext在WCF中是一个非常重要、也是一个十分有用的对象,它代表服务操作执行的上下文。我们可以通过静态属性Current(OperationContext.Current)得到当前的OperationContext。借助OperationContext,我们可以在服务端或者客户端获取或设置一些上下文,比如在客户端可以通过它为出栈消息(outgoing message)添加SOAP报头,以及HTTP报头(比如Cookie)等。在服务端,则可以通过OperationContex获取在客户端设置的SOAP报头和HTTP报头。关于OperationContext的详细信息,可以参阅MSDN在线文档。
配置预定义绑定类型
在WCF预定义绑定类型中,WSDualHttpBinding和NetTcpBinding均提供了对双工通信的支持,但是两者在对双工通信的实现机制上却有本质的区别。WSDualHttpBinding是基于HTTP传输协议的;而HTTP协议本身是基于请求-回复的传输协议,基于HTTP的通道本质上都是单向的。WSDualHttpBinding实际上创建了两个通道,一个用于客户端向服务端的通信,而另一个则用于服务端到客户端的通信,从而间接地提供了双工通信的实现。而NetTcpBinding完全基于支持双工通信的TCP协议。
<service name="DuplexService.CalculatorService">
<endpoint address="" binding="wsHttpBinding" contract="DuplexService.ICalculatorService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/DuplexService/CalculatorService/" />
</baseAddresses>
</host>
</service>
我们现在暂时就用wsDualHttpBinding.然后我们创建一个winForm应用程序,再添加服务引用DuplexServiceTest。
然后我们实现在上面服务端建立的客户端回调接口
需要引用我们引用的服务类using Client.DuplexServiceTest
看下面ClientCallBack类实现的接口是ICalculatorServiceCallback,而不是我们原先创建的接口IClientCallBack。
而在客户端引用中生成的副本为
所以我们需要在Form1.cs文件上引用using Client.DuplexServiceTest。
接下来我们在From中添加一个按钮,然后通过点击按钮来进行服务的调用,通过InstanceContext服务上下文进行双工服务的调用。
private void button1_Click(object sender, EventArgs e)
{
InstanceContext instanceContext = new InstanceContext(new ClientCallBack());
DuplexServiceTest.CalculatorServiceClient csc = new CalculatorServiceClient(instanceContext);
csc.Test(11, 22);
}
点击按钮看效果,就如上图所示。
将示例代码上传,可以点击下载