WCF从零学习之设计和实现服务协定(二)
在创建服务协定之前,有很多WCF术语,比如:
消息、服务、终结点
创建协定
类或接口都可以定义服务协定,建议使用接口,因为接口可以直接对服务协定建模
服务协定接口具有托管接口的所有优点:
服务协定接口可以扩展任何数量的其他服务协定接口。
一个类可以通过实现服务协定接口来实现任意数量的服务协定。
可以通过更改接口实现来修改服务协定的实现,而让服务协定保持不变。
可以通过实现旧接口和新接口来确定服务的版本。老客户端连接到原始版本,而新客户端则可以连接到比较新的版本
定义服务协定:
在类或接口上使用ServiceContractAttribute属性标记
定义服务操作:
在方法上使用OperationContractAttribute属性对其进行标记
参数和返回值
每个操作都有一个返回值和一个参数,即使它们为void。可以使用局部方法将对象的引用从一个对象传递到另一个对象,但与局部方法不同的是,服务操作不会传递对象的引用,而是传递对象的副本,也就是重新复制一份。
参数和返回值中使用的每个类型都必须是可序列化的。
默认情况下,基元类型是可序列化的
创建服务协定-服务操作的消息模式
- 请求/答复
[OperationContact]
string Hello(string str);
操作的结构是除非客户端异步调用操作,否则客户端将停止处理,直到收到返回消息,即使该消息正常情况下为空时也是如此。
- 单向
如果WCF服务应用程序的客户端不必等待操作完成,并且不处理SOAP错误,则该操作可以指定单向消息模式。
若要为返回void的操作指定单向消息交换,请将IsOneWay属性设置为 true,默认为false,即请求/答复模式
[OperationContact(IsOneWay=true)]
void Hello(string str);
- 双工
双工模式的特点是,无论使用单向消息发送 还是请求/答复消息发送方式,服务和客户端均能独立的向对方发送消息(服务器端也能向客户端请求)。对于必须直接与客户端通信或消息交换的任意一方提供异步体验(包括类似于事件的行为)的服务来说,这种双向通信形式非常有用。
若要设计双工协定,还必须设计回调协定,并将该回调协定的类型分配给标记服务协定的ServiceContractAttribute属性的CallbackContract属性,如要实现双工模式,必须创建第二个接口,该接口包含在客户端调用的方法声明
[ServiceContract(SessionMode=SessionMode.Required,CallbackContract=typeof(ICalculatorDuplexCallback))]//SessionMode会话的服务,实例的模式是唯一的,每个会话创建一个实例
public interface ICalculatorDuplex
{
[OperationContract(IsOneWay=true)]
void Clear();
}
public interface ICalculatorDuplexCallback
{
//客户端回调方法
[OperationContract(IsOneWay=true)]
void Equals(double result);
}
接下来进行双工模式的简单案例
WCF的WebConfig代码:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<bindings />
<client />
<services>
<service name="WcfService2.Service1" behaviorConfiguration="WcfServiceLibrary2.Service1Behavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:27322/Design_Time_Addresses/WcfServiceLibrary2/CalculatorService/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="" binding="wsDualHttpBinding" contract="WcfService2.IService1">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WcfServiceLibrary2.Service1Behavior">
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
创建数据协定(DataContract)
为了获得最大可能的互操作微软平台和非微软平台,建议使用DataContractAttribute和DataMemberAttribute属性对自定义类型数据协定进行标记,以创建数据协定。如果不加上数据协定,数据类型是不会被序列化的,当然也可以使用其他序列化机制。标准ISerializable,SerializableAttribute和IXmlSerializable机制都可用于处理数据类型到基础SOAP消息的序列化,这些消息可将数据类型从一个应用程序带到另一个应用程序
使用out和ref参数
由于out和ref参数都表示将操作的值返回,所以操作协定的模式不能是单向模式,即IsOneWay=true