WCF技术剖析(卷1)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.1 EndpointAddress

WCF中的地址通过System.ServiceModel.EndpointAddress类型表示。上面列出的关于地址提供的3个典型功能,分别对应着EndpointAddress的3个重要的组成部分,它们可以通过EndpointAddress的3个属性成员来表示:URI、Headers和Identity。

        public class EndpointAddress
        {
            //其他成员
            public Uri                         uri { get; }
            public AddressHeaderCollection     Headers { get; }
            public EndpointIdentity            Identity { get; }
        }

1.URI

一个统一资源标识符(URI:Uniform Resource Identifier),唯一标识一个确定的可以访问的服务,同时也定位该服务所在的地址。比如http://artech.com:8888/CalculatorService。该地址可能是部署服务真正的物理地址,也可能是一个逻辑地址。关于URI,会在下面一节中进行详细介绍。

2.AddressHeader

WCF采用基于消息(Message)的通信方式,虽然通过WCF可以以REST/POX的方式创建和消费服务,但是最常用的还是基于SOAP的消息交换方式。一个SOAP消息是一个自描述(Self-Descriptive)的实体,它不仅仅包含对于服务调用本身的描述,还包含实现相关辅助功能的控制信息,比如寻址信息、安全凭证等。一个SOAP消息由一个消息主体(Body)和若干报头(Header)组成。一般地,基于服务调用的内容作为有效负载(Payload)驻留于消息主体部分,而其他相关的控制信息则被置于相应的报头中,随着有效负载一起被传输。

注:REST(Representational state transfer)是一种构建超媒体(HyperMedia)系统的软件构架风格。REST可以看成是一种面向资源的软件架构(ROA:Resource Oriented Architecture),它将所有的状态和功能均抽象成可以被访问的资源。基于WWW(World Wide Web)的RESTFul应用是REST最为典型的应用实践,在WWW下,HTTP提供了一种统一的资源访问方式,比如URI、Method(GET、POST、PUT和DELETE)、Status Code、MIME Type等。RESTful WCF服务无须遵循严格的消息格式,所以它采用单纯XML格式(POX:Plain of XML)消息。

一般地,EndpointAddress的URI代表着服务真正被部署的地址,我们将这种类型的地址称为物理地址(Physic Address)。但是在某些情况下,比如涉及NAT、DHCP及防火墙的场景中,服务的真实地址往往是一个私有地址,或者是一个动态地址(比如动态获取IP)。我们必须将服务的地址指定成一个固定的共有地址,在真正进行消息交换的时候,再通过一些路由机制将消息发送到真正的目标地址。这样的地址被称为逻辑地址(Logical Address)。

注:NAT(Network Address Translator),负责进行不可以路由(Non-routable)的私有地址(或者本地址)与可路由(Routable)的Internet地址之间的转换。DHCP(Dynamic Host Configuration Protocol),负责进行IP的动态分配。

对于物理地址和逻辑地址相互分离的情形,往往须要采用手工寻址(Manual Addressing)的方式进行消息的发送、接收、处理与转发。手工寻址往往依赖于一些额外的寻址信息,EndpointAddress的Headers属性就是为此设计的。在客户端,对于用于访问服务的终结点,通过EndpointAddress的Headers属性设置协助手工寻址相关的辅助信息,该信息将最终出现在SOAP消息的报头中,随着消息主体发往目标地址。

虽然起名为AddressHeader,但它的内容不限于寻址信息,实际上你可以将任意的内容添加到AddressHeader中,并最终成为SOAP报头。AddressHeader并非仅仅局限于客户端的终结点,在服务端可以借助它实现基于终结点地址的消息筛选功能。

比如,对于同一个服务,有两种不同类型的消费者:一种是真正购买了该服务的使用者,另一种则是一般的试用者。而我们的服务分别寄宿在两台具有不同性能的主机上,为了优先保证前一种用户的正常使用,希望将对他们的访问请求递交到具有高性能的主机上,而将试用者的服务访问请求递交到另一台性能一般的主机上。那么就可以在对服务进行寄宿的时候,指定不同的Address Header给不同的终结点。当客户点的请求抵达服务端,服务端的消息分发系统会根据SOAP消息的目的地址(在SOAP消息中To报头指定的URI)和AddressHeader来选择对应的终结点进行进一步处理。对于消息筛选放在本章后续部分予以介绍。

3.EndpointIdentity

在一个分布式应用环境中,安全(Security)往往是最重要,同时也是最难实现的功能。对于一个安全系统(Security Infrastructure)来说,身份的识别或身份验证(Identity Authentication)往往又是整个安全框架的基础。但对于身份验证,习惯了传统的C/S架构的读者首先想到的可能是对访问者的身份验证。但在一个基于SOA的架构中,在对服务进行调用之前确定服务的真实身份同样是必不可少的。关于双向验证(Mutual Authentication),将在下一卷予以详细介绍。

在WCF中,服务的身份通过EndpointIdentity这样一个特殊的对象表示。在进行服务的寄宿时,通过代码或配置的方式创建基于某种身份识别类型的EndpointIdentity对象,并将其指定到对应终结点的EndpointAddress上。典型的服务身份识别类型包括:基于用户账号名称的UPN(User Principle Name)、基于服务账号名称的SPN(Service Principle Name)、DNS名称、RSA键值及X.509证书等。EndpointIdentity表示的关于服务身份的信息将作为元数据(metadata)的一部分发布到WSDL中。服务的访问者,可以利用代码生成工具(比如SvcUtil.exe)通过WSDL导入元数据自动生成客户端的代码和具有服务身份信息的配置。如果你确切知道服务端使用的EndpointIdentity,也可以通过手工的方式配置,或者以代码的方式指定该EndpointIdentity。

在安全(Security)允许的情况下,当客户点通过服务代理进行服务调用的时候,WCF系统将首先对服务的真实身份进行验证,以确保该服务正是客户端希望访问的服务。关于EndpointIdentity和服务验证,在下一卷中将予以详细介绍。