服务模型层概述

WWSAPI 服务模型 API 将客户端与服务之间的通信建模为方法调用,而不是数据消息。 与支持客户端和服务之间更传统消息交换的通道层相比,服务模型通过客户端上的服务代理和服务主机上的服务主机自动管理通信。 这意味着客户端调用生成的函数,服务器实现回调。

例如,假设计算器服务对两个数字执行加法和减法。 加法和减法是自然表示为方法调用的操作。

显示计算器服务如何使用加法和减法方法调用与客户端通信的关系图。

服务模型将客户端与服务之间的通信表示为声明的方法调用,因此对应用程序隐藏基础通道层的通信详细信息,使服务更易于实现。

指定服务

必须根据其消息交换模式及其网络数据表示形式来指定服务。 对于服务,此规范通常以 WSDL 和 XML 架构文档的形式提供。

WSDL 文档是一个 XML 文档,其中包含服务的通道绑定和消息交换模式,而 XML 架构文档是定义单个消息的数据表示形式的 XML 文档。

对于计算器服务及其加法和减法操作,WSDL 文档可能如以下示例所示:

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" 
xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" 
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:wsa10="http://www.w3.org/2005/08/addressing" 
xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:portType name="ICalculator">
  <wsdl:operation name="Add">
   <wsdl:input wsaw:Action="http://Example.org/ICalculator/Add" 
   message="tns:ICalculator_Add_InputMessage" />
   <wsdl:output wsaw:Action="http://Example.org/ICalculator/AddResponse" 
   message="tns:ICalculator_Add_OutputMessage" />
  </wsdl:operation>
 </wsdl:portType>
</wsdl:definitions>

同样,其 XML 架构可以定义如下:

<xs:schema xmlns:tns="http://Example.org" elementFormDefault="qualified" 
targetNamespace="http://Example.org" xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xs:element name="Add">
  <xs:complexType>
   <xs:sequence>
    <xs:element minOccurs="0" name="a" type="xs:int" />
    <xs:element minOccurs="0" name="b" type="xs:int" />
   </xs:sequence>
  </xs:complexType>
 </xs:element>
 <xs:element name="AddResponse">
  <xs:complexType>
   <xs:sequence>
    <xs:element minOccurs="0" name="result" type="xs:int" 
    />
   </xs:sequence>
  </xs:complexType>
 </xs:element>
</xs:schema> 

将元数据转换为代码

服务模型提供 WsUtil.exe 作为处理这些元数据文档的工具,将 WSDL 文件转换为 C 标头和源文件。

显示WsUtil.exe如何将 WSDL 文件转换为 C 头文件和源文件的关系图。

WsUtil.exe为服务实现生成标头和源,并为客户端 生成客户端服务操作。

从客户端调用计算器服务

与服务实现一样,客户端必须包含生成的一个或多个标头。

#include "CalculatorProxyStub.h"

现在,客户端应用程序可以创建并打开服务代理,以开始与计算器服务通信。

WS_ENDPOINT_ADDRESS address = {0};
WS_STRING uri= WS_STRING_VALUE(L"http://localhost/example");
address.uri = uri;

if (FAILED (hr = WsCreateServiceProxy(WS_CHANNEL_TYPE_REQUEST, WS_HTTP_CHANNEL_BINDING, NULL, NULL, 0, &serviceProxy, error)))
    goto Error;

if (FAILED (hr = WsOpenServiceProxy(serviceProxy, &address, NULL, error)))
    goto Error;

应用程序可以使用以下代码调用计算器服务上的 Add 操作:

if (FAILED (hr = DefaultBinding_ICalculator_Add(serviceProxy, heap, 1, 2, &result, NULL, 0, NULL, error)))
    goto Error;

有关计算器服务的完整实现,请参阅 HttpCalculatorClientExample 中的代码示例。

服务模型组件

计算器示例中各个 WWSAPI 服务模型组件的交互如下所示:

  • 客户端创建 服务代理 并将其打开。
  • 客户端调用服务的 Add 函数,并传入服务代理。
  • 消息根据元数据工具生成的标头和源文件中的序列化元数据 (WsUtil.exe) 进行序列化。
  • 消息将写入通道,并通过网络传输到服务。
  • 在服务器端,服务托管在服务主机内,并且有一个侦听 ICalculator 协定的终结点。
  • 使用存根中的服务模型元数据,服务从客户端反序列化消息,并将其调度到存根。
  • 服务器端服务调用 Add 方法,并向其传递操作上下文。 此操作上下文包含对传入消息的引用。

显示各个 WWSAPI 服务模型组件交互的关系图。

组件

  • 服务主机:承载服务。
  • 服务代理:定义客户端与服务通信的方式。
  • 上下文:使特定于状态的信息可供服务操作使用的属性包。
  • 协定:服务的接口定义。 例如,ICalculator 在我们的示例代码中表示计算器服务的协定。
  • WsUtil.exe:用于生成代理和存根的服务模型元数据工具。