WCF的所有服务都会公开为契约(Contract)。契约与平台无关,是描述服务功能的标准方式。WCF定义了四种类型的契约。

1、服务契约(Service Contract)

服务契约描述了客户端能够执行的服务操作。

2、数据契约(Data Contract)

数据契约定义了与服务交互的数据类型。WCF为内建类型如int和string隐式地定义了契约;我们也可以非常便捷地将定制类型定义为数据契约。

3、错误契约(Fault Contract)

错误契约定义了服务抛出的错误,以及服务处理错误和传递错误到客户端的方式。

4、消息契约(Message Contract)

消息契约允许服务直接与消息交互。消息契约可以是类型化的,也可以是非类型化的。如果系统要求互操作性,或者遵循已有消息格式,那么消息契约会非常有用。WCF开发者极少使用消息契约。

服务契约

 
  
  1. [ServiceContract]  
  2. interface IMyContract  
  3. {  
  4.     [OperationContract]  
  5.     string MyMethod(string text);  
  6.  
  7.     //不会成为契约的一部分  
  8.     string MyOtherMethod(string text);  
  9. }  
  10.  
  11. class MyService:IMyContract  
  12. {  
  13.     public string MyMethod(string text)  
  14.     {  
  15.         return "Hello "+text;  
  16.     }  
  17.  
  18.     public string MyOtherMethod(string text)  
  19.     {  
  20.         return "Cannot call this method over WCF";  
  21.     }  

ServiceContract特性可以将一个CLR接口映射为与技术无关的服务契约。ServiceContract特性公开了CLR接口(或者类)作为WCF契约。如果接口没有标记ServiceContract特性,WCF客户端则无法访问它。这一特点遵循了面向服务的一个原则,即明确的服务边界。为满足这一原则,所有契约必须明确要求:只有接口(或者类)可以被标记为ServiceContract特性,从而被定义为WCF服务,其他类型都不允许。

在标记为ServiceContract特性的服务契约中,必须使用OperationContract特性显示表明哪些方法需要暴露为WCF契约中的一部分。WCF只允许将OperationContract特性应用到方法上,而不允许应用到同样属于CLR概念的属性、索引器和事件上。此外,契约操作不能使用引用对象作为参数,只允许使用基本类型或数据契约。

应用ServiceContract特性

一个单独的类通过继承和实现多个标记了ServiceContract特性接口,可以支持多个契约。

服务类还有一些实现上的约束,我们要避免使用带参构造函数,因为WCF只能使用默认构造函数。

应尽量避免将ServiceContract特性直接应用到服务类上,而应该定义一个单独的契约,这有利于在不同场景下使用契约。

名称与命名空间

可以为契约定义命名空间。契约的命名空间具有与.NET编程相同的目的:确定契约类型范围,以降低类型的冲突几率。可以使用ServiceContract类型的Namespace属性设置命名空间:

 
  
  1. [ServiceContract(Namespace="MyNamespace")]  
  2. interface IMyContract  
  3. {...} 

若非特别指定,契约的默认命名空间为http://tempuri.org。对外服务的命名空间通常使用公司的URL;至于企业网(Intranet)内部服务的命名空间,则可以定义有意义的唯一名称,例如MyApplication。

在默认情况下,契约公开的名称就是接口名。但是也可以使用ServiceContract特性的Name属性为契约定义别名,从而在客户端的元数据(Metadata)中公开不同的名称:

 
  
  1. [ServiceContract(Name="IMyContract")]  
  2. interface IMyOtherContract  
  3. {...} 

相似的,操作公开的名称默认为方法名,但我们同样可以使用OperationContract特性的Name属性设置别名,从而公开不同的操作名:

 
  
  1. [ServiceContract]  
  2. interface IMyContract  
  3. {  
  4.     [OperationContract(Name="SomeOperation")]  
  5.     void MyMethod(string text);