WCF学习笔记 4

2019-08-29 18:03:57 浏览数 (1)

WCF学习笔记之契约(Contract)

初识契约(Contract)

契约简单讲就是服务端和客户端进行消息交换定义的一种交换协议。

在wcf中服务契约的定义涉及到这两个自定义特性:

代码语言:javascript复制
System.ServiceModel.ServiceContractAttribute
System.ServiceModel.OperationContractAttribute

其中应用在ServiceContractAttribute服务契约特性上的特性[AttributeUsage(AttributeTargets.Class)]表示服务契约特性只能应用于类或接口。

应用在OperationContractAttribute服务契约特性上的特性[AttributeUsage(AttributeTargets.Method)]表示操作契约特性只能应用于方法成员。

ServiceContractAttribute特性具有以下一些成员:

代码语言:javascript复制
public sealed class ServiceContractAttribute : Attribute
{
  public Type CallbackContract { get; set; }
  
  public string ConfigurationName { get; set; }
   
  public bool HasProtectionLevel { get; }
 
  public string Namespace { get; set; }
   
  public ProtectionLevel ProtectionLevel { get; set; }
  
  public SessionMode SessionMode { get; set; }
}

我们在定义一个类或接口时为该类型应用[ServiceContract]特性,同时还可以指定服务契约的一个或多个属性,最常用的就是指定命名空间和名称,比如:

代码语言:javascript复制
[ServiceContract(Name="CalculatorService",Namespace=”http://www.ainote.cn”)]

服务契约在终结点配置项的contract属性中所表示的值,也是服务契约的ConfigurationName属性的值,默认是服务契约类型的完全名称(服务契约的CLR类型名称),我们也可以配置 ServiceContract 特性的ConfigurationName属性值来指定一个契约配置名称。

服务契约的默认配置Stone.Contract.Contract.ICalculator:

代码语言:javascript复制
<endpoint 
  address="http://127.0.0.1:126/CalculatorService"
    binding="wsHttpBinding"
    contract="Stone.Contract.Contract.ICalculator">
</endpoint>

通过ConfigurationName属性指定一个配置值CalculatorCatract:

代码语言:javascript复制
<endpoint 
  address="http://127.0.0.1:126/CalculatorService"
    binding="wsHttpBinding"
    contract="CalculatorCatract">
</endpoint>

在双工通信模式下面还需要在ServiceContract特性应用中指定CallbackContract类型typeof(ICalculatorCallback):

代码语言:javascript复制
[ServiceContract(Name="CalculatorService",Namespace="http://www.ainote.cn",
ConfigurationName="CalculatorCatract",CallbackContract=typeof(ICalculatorCallback))]
public interface ICalculator
{
}

OperationContractAttribute特性具有以下一些成员:

代码语言:javascript复制
public sealed class OperationContractAttribute : Attribute
{
   public string Action { get; set; }
   public bool AsyncPattern { get; set; }
   public bool HasProtectionLevel { get; }
   public bool IsOneWay { get; set; }
   public string Name { get; set; }
   public ProtectionLevel ProtectionLevel { get; set; }
   public string ReplyAction { get; set; }
}

在我们定义的服务类型里面需要指定一组操作方法,这些操作方法要作为契约的一部分必须应用[OperationContract],同时还可以指定操作契约的一个或多个属性,最常用的就是指定Name、Action和ReplyAction。因为服务契约里面的每个操作都要有一个唯一的名称,所以面向对象编程的重载要素在这儿就不适用,不过我们可以通过为重名的每个操作方法的操作契约的名称属性设置一个唯一的名称来表示这个操作方法的重载,如以下设置:

代码语言:javascript复制
[ServiceContract(Name = "CalculatorService", Namespace = "http://www.ainote.cn")]
public interface ICalculator1
{
  [OperationContract(Name = "AddDouble")]
  double Add(double x, double y);
  [OperationContract(Name = "AddInt")]
  int Add(int x, int y);
}

[OperationContract]的Action和ReplyAction属性,默认情况下Action和ReplyAction属性的值是有服务契约命名空间、服务契约的名称以及操作名称三者共同组成。

比如:http://www.ainote.cn/CalculatorService/Add ReplyAction属性的值则是在Action属性值的基础上加上Reply后缀。

我们也可以在服务契约里面为这两个属性指定一个唯一的值。如:

代码语言:javascript复制
[ServiceContract(Name="CalculatorService",Namespace="http://www.ainote.cn",
    ConfigurationName="CalculatorCatract",CallbackContract=typeof(ICalculatorCallback))]
public interface ICalculator
{
  [OperationContract(Name = "AddDouble", Action = "http://www.ainote.cn/CalculatorService/AddDouble",
    ReplyAction = "http://www.ainote.cn/CalculatorService/AddDoubleReply")]
  double Add(double x, double y);
  
  [OperationContract(Name = "AddInt", Action = "http://www.ainote.cn/CalculatorService/AddInt",
    ReplyAction = "http://www.ainote.cn/CalculatorService/AddIntReply")]
  int Add(int x, int y);
}

服务契约的继承

服务契约本质上是一个类或接口,所以他具有面向对象的一些特征。

ServiceContractAttribute特性所应用的AttributeUsage的Inherited属性设置为false,所以服务契约不具有继承性。

OperationContractAttribute特性所应用的AttributeUsage的Inherited属性设置为true,所以具有继承性。

不过为了支持服务契约的继承性我们必须通过在派生类型上应用ServiceContractAttribute特性。

0 人点赞