Microsoft Indigo 简介(2)

来源:互联网 发布:濮阳市网络公务员 编辑:程序博客网 时间:2024/05/01 13:10
三、创建 Indigo 服务

如下图所示,每个 Indigo 服务均由三个部分构成:

一个“服务类”,采用 C# 或 VB.NET 或其他基于 CLR 的语言编写,实现一个或多个方法;

一个“宿主”环境,这是一种应用程序域和进程,服务将在该环境中运行。

一个或多个“终结点”,由客户端用于访问服务。

与 Indigo 服务的所有通信均需通过该服务的终结点实现。每个终结点将指定一个“合同”,确定通过该终结点可以访问哪些方法;一个“绑定”,确定客户端如何与该终结点通信;以及一个“地址”,指示可在什么地方找到该终结点。

理解 Indigo 需要掌握所有这些概念。本节将从服务类开始逐一描述每个概念。

创建服务类

Indigo 服务类就像其他任何类一样,但它还有一些新特性。这些新特性允许该类的创建者定义该类实现的一个或多个“合同”。每个 Indigo 服务类至少应实现一个“服务合同”,用于定义该服务提供的操作。服务类还可以显式实现一个“数据合同”,用于定义那些操作传递的数据。本节将从服务合同开始对两者进行探讨。

定义服务合同

每个 Indigo 服务类均需实现一些方法,以供其客户端使用。服务类的创建者通过将这些方法包含在某个服务合同中,来决定将哪些方法公开为客户可调用的操作。定义服务合同,实际上通常就是显式使用服务,对 .NET 领域来说基本上是一个新观念。Indigo 的创建者需要找到一条途径,从 CLR 以及在其基础上构建的编程语言的角度来把握这一观念。幸运的是,CLR 的创建者们早就预见到了这种扩展需求,因而提供了对“属性”的支持。从开发人员的角度来看,属性就是一些字符串,可能具有关联的属性,它们可能出现在类定义、方法定义的前面,也可能出现在其他位置。只要有属性出现,它就会改变其所关联的事物的某些行为。

.NET Framework 从初始版本开始就对各种事物使用了属性。例如,在 .NET Framework 的 ASMX 技术中要使一个方法成为 SOAP 可调用的 Web 服务,该方法将被前置一个 WebMethod 属性。与此相似,企业服务使用 Transaction 属性来指示一个方法需要事务。Indigo 将这种观念用于服务,定义了大量属性来定义和控制服务。

Indigo 中最基本的属性是 ServiceContract。实际上,Indigo 服务类本身就是标记有 ServiceContract 属性的类或者是实现了标记有该属性的接口的类。以下是采用第一种方法的一个简单 C# 示例:

using System.ServiceModel;[ServiceContract]class Calculator{[OperationContract]private int Add(int a, int b) {return a + b;  }   [OperationContract]public int Subtract(int a, int b) {return a - b; }   public int Multiply(int a, int b) {return a * b; }} 

ServiceContract 属性以及 Indigo 使用的所有其他属性均在 System.ServiceModel 命名空间中定义,因此本例开头使用 using 语句来引用该命名空间。服务类中可被客户端调用的每个方法都必须使用名为 OperationContract 的另一个属性加以标记。服务类中带有前置 OperationContract 属性的所有方法都将自动被 Indigo 公开为 SOAP 可调用操作。在本例中,Add 和 Subtract 均标记有该属性,因此两者均对该服务的客户端公开。服务类中未标记有 OperationContract 的任何方法(如上例中的 Multiply)将不包含在服务合同中,因而不能被该 Indigo 服务的客户端调用。

服务和对象,这两个本来互不相干的抽象,在 Indigo 中却走到了一起。必须理解的是,两者均显式或隐式地依赖于合同来定义它们将向外界公开什么。通过类定义的对象有效地定义了一种合同,此合同决定了它的哪些方法可以被同一应用程序中的其他对象调用。对这些方法的访问由语言关键字如 public 和 private 控制。例如,在上面所示的类 Calculator 中,同一应用程序中的其他对象可以调用该类的两个公共方法 Subtract 和 Multiply。该类公开的对象合同中只包含这两个方法。

通过 Indigo 的属性,Calculator 还定义了一个服务合同,如前所述。此合同也拥有两个方法,但它们与对象合同中的那些方法不同。一个方法能否被此 Indigo 服务的客户端调用,由 OperationContract 属性控制,而不是由 public 和 private 关键字控制。由于此属性只出现在 Add 和 Subtract 上,因此只有这两个方法才能被客户端调用。对象合同与服务合同彼此完全独立,正因如此,同一方法(如 Add)才可以既是 private 同时又具有 OperationContract 属性。

刚才的示例展示了创建 Indigo 服务类的最简单方法:直接使用 ServiceContract 标记类。这样做之后,该类的服务合同将隐含定义为包含该类中所有标记有 OperationContract 的方法。还可以(并且大多数情况下这样做会更好)使用语言中的 interface 类型显式地指定服务合同。使用这种方法,Calculator 类可能会如下所示:

using System.ServiceModel;[ServiceContract]public interface ICalculator{[OperationContract]private int Add(int a, int b);[OperationContract]public int Subtract(int a, int b);}class Calculator :ICalculator{private int Add(int a, int b) {return a + b;  }   public int Subtract(int a, int b) {return a - b; }   public int Multiply(int a, int b) {return a * b;  }} 

在本例中,ServiceContract 和 OperationContract 属性被指定到 ICalculator 接口及其包含的方法,而不是 Calculator 类本身。但结果是相同的,因此这一版本的服务公开的服务合同与前一版本相同。像这样使用显式接口稍微有点复杂,但同时也具有更大的灵活性。例如,一个类可以实现多个接口,这意味着它也可以实现多个服务合同。通过公开多个终结点,每个终结点拥有一个不同的服务合同,一个类就可以向不同的客户端提供不同的服务组。

最后一点:使用 ServiceContract 和 OperationContract 标记服务类还允许以 Web 服务描述语言 (WSDL) 自动生成服务合同定义。因此,可将每个 Indigo 服务合同的外部可见定义作为指定该合同中的操作的标准 WSDL 文档来访问。虽然本文不作讲解,但直接从 WSDL 文档创建 Indigo 服务类的做法同样是可行的,这一方法对于实现外部定义的 WSDL 接口十分有用。

定义数据合同

Indigo 服务类指定了一个服务合同,该服务合同定义了将向服务客户端公开哪些方法。这些操作中的每个操作一般都将传递一些数据,即一个服务合同还隐含有某种数据合同,该数据合同用以描述将被交换的信息。有些情况下,这种数据合同被作为服务合同的一部分来隐含定义。例如,在上面所示的 Calculator 类中,每个方法使用了两个整数型输入参数并返回一个整数。这些参数定义了此服务交换的所有数据,因此它们包含服务的数据合同。对于这种每个操作仅使用简单类型的服务,在服务合同内隐含定义该合同的数据特性较为恰当。无需再进行任何其他操作。

但服务还可能拥有更复杂类型的参数,如结构。在这种情况下,就需要使用显式数据合同。数据合同定义内存中的类型如何转换为适合通过线路传输的形式,即所谓的“序列化”过程。实际上,数据合同是控制数据如何序列化的一种机制。

在 Indigo 服务类中,数据合同使用 DataContract 属性来定义。标记有 DataContract 的类、结构或其他类型都可以拥有一个或多个带有前置 DataMember 属性的成员,指示该成员必须被包含在此类型的序列化值中。以下是一个简单示例:

[DataContract]struct Customer {[DataMember] public string Name; int public age;[DataMember] private int CreditRating;}

当将此 Customer 类型的实例作为一个参数在标记有 OperationContract 的方法中传递时,将只有那些标记有 DataMember 属性的字段(Name 和 CreditRating)被传递。

字段标记为 public 或 private 对该字段是否被序列化没有影响。就像方法的情况一样,public 和 private 关键字是定义此类型如何被同一应用程序中的其他对象访问的合同的一部分。DataMember 则像 OperationContract 一样,定义该类型如何被此类所实现的服务的客户端访问。两者再次完全独立。

关于 Indigo 合同需要强调的最后一点是,没有任何东西默认成为服务合同或数据合同的一部分。相反,开发人员必须显式地使用 ServiceContract 和 DataContract 属性指示哪些类型拥有 Indigo 定义的合同,然后使用 OperationContract 和 DataMember 属性显式地指定这些类型的哪些部分向此服务的客户端公开。其设计者的基本原则之一便是服务必须拥有显式边界,因此 Indigo 是一种明确选择技术。服务要向其客户端提供的任何事物均需在代码中明确指定。

合同以及用于定义它们的那些属性是 Indigo 的主要特性,此处的简短描述仅涵盖了最显著的部分。OperationContract 属性可用于定义“单向”操作,例如不需要应答的服务调用。还可通过创建“双工”合同定义双方均可充当客户端和服务的交互操作,每一方均可调用操作并公开对方调用的操作。DataContract 属性同样拥有多个选项,甚至可以使用一个称为 MessageContract 的属性直接与 SOAP 消息进行内部交互。Indigo 提供的大部分操作均通过合同来表示,因此合同是其最基本的概念。