使用 SOAP 扩展修改 SOAP 消息

本主题专门介绍一项旧有技术。现在应通过使用以下链接来创建 XML Web 服务和 XML Web 服务客户端: Windows Communication Foundation.

利用 SOAP 扩展,开发人员可以更改发往和来自 Web 服务或 Web 服务客户端的 SOAP 消息,从而扩充 Web 服务的功能。例如,您可以实现要使用现有的 Web 服务运行的加密或压缩算法。

若要了解 SOAP 扩展的工作原理,需要先了解 Web 服务的生存期。有关更多信息,请参见 XML Web services 生存期分析

下面的插图显示了客户端调用 Web 服务的主要阶段。

XML Web services 生存期

从图中可以看出,.NET Framework 序列化和反序列化 XML 是在处于 Web 服务计算机和 Web 服务客户端计算机上的阶段时进行的。通过向基础结构中注入 SOAP 扩展,可以检查或修改每个序列化和反序列化阶段前后的 SOAP 消息。例如,加密 SOAP 扩展可以在 .NET Framework 序列化客户端参数之后对 SOAP 消息的 XML 部分进行加密,而在 .NET Framework 反序列化该 SOAP 消息之前,它又可以在 Web 服务器上对该 SOAP 消息进行解密。SOAP 扩展可能检查或修改 SOAP 消息的这些阶段在 SoapMessageStage 枚举中定义。在本示例中,SOAP 扩展在 AfterSerialize 阶段执行加密并在 BeforeDeserialize 阶段执行解密。

通常情况下,当 SOAP 扩展修改 SOAP 消息的内容时,必须在客户端和服务器上都执行修改。这就是说,如果有 SOAP 扩展要在客户端上运行并对 SOAP 消息进行加密,必须存在相应的 SOAP 扩展在服务器上对 SOAP 消息进行解密。如果不对 SOAP 消息进行解密,ASP.NET 基础结构便无法将 SOAP 消息反序列化为对象。

当然,不修改 SOAP 消息的 SOAP 扩展(例如只记录 SOAP 消息的 SOAP 扩展)只能在客户端或服务器上运行。在这种情况下,接收方收到的 SOAP 消息将与没有运行 SOAP 扩展时一样,因而 ASP.NET 基础结构可以反序列化 SOAP 消息。另外,如果 SOAP 扩展修改 SOAP 的方式使得 ASP.NET 基础结构可以对其进行反序列化,则不需要在客户端和服务器上都运行该 SOAP 扩展。

扩展 SOAPExtension 类

若要实现 SOAP 扩展,请从 SoapExtension 类派生一个类。您应当或必须实现 SOAPExtension 类的三个方法:

有关如何实现这些方法的分步说明,请参见主题“演练:使用 SOAP 扩展更改 SOAP 消息”。

ChainStream 方法接收 Stream 对象并返回 Stream 对象。当 SOAP 扩展在每个 SoapMessageStage 中执行并修改 SOAP 消息时,另一个 SOAP 扩展应从传入 ChainStreamStream 中读取数据,并向从 ChainStream 返回的 Stream 中写入数据。因此,必须在 ChainStream 方法内部将两个 Stream 引用都分配给成员变量。

SoapExtension 派生的类将基于其适用的 Web 服务或 Web 服务方法使用 GetInitializerInitialize 方法初始化内部数据。例如,记录发往和来自 Web 服务方法的 SOAP 消息的 SOAP 扩展可以初始化一个文件名,以保存日志记录信息(基于 SOAP 扩展与之一起运行的 Web 服务或 Web 服务方法的名称)。

Web 服务基础结构调用 GetInitializer 方法的时间以及向该方法传递的参数取决于 SOAP 扩展的配置方式,如下所述:

  • 如果使用特性配置 SOAP 扩展,则在首次访问 Web 服务 method 时,Web 服务基础结构将调用 GetInitializer

  • 如果在配置文件中配置 SOAP 扩展,则只有在首次访问整个 Web 服务时,Web 服务基础结构才会调用 GetInitializer

Web 服务基础结构会缓存 GetInitializer 方法返回的对象。随后,每当 SOAP 扩展使用该 Web 服务或 Web 服务方法运行时,Web 服务基础结构都会将该初始值设定项对象传递给 Initialize 方法。

实际上,在标准 SOAP 处理基础上扩展的处理部分将由 ProcessMessage 方法执行。每当 Web 服务基础结构调用 ProcessMessage 时,它都会(以参数形式)传递从 SoapMessage 派生的类的一个实例,该实例包含有关该特定阶段中 SOAP 消息的信息。如果 SOAP 扩展要与 Web 服务一起运行,则会传入一个 SoapServerMessage 对象。如果 SOAP 扩展要与 Web 服务客户端一起运行,则会传入一个 SoapClientMessage 对象。

Soap 扩展和异常

Soap 扩展本身永远不得引发异常。但是,它们可以将异常信息添加到传入 ProcessMessage 方法的 SoapMessage 对象的 Exception 属性中。

此外,它们还可以充当应用程序范围的异常处理程序,以使用同一工具捕捉为其安装 SOAP 扩展的应用程序中的所有异常,并可以执行其他一些任务(例如,修改返回的 SOAP 错误)。

SOAP 扩展方法的调用顺序

现在您已经学习了 SOAP 扩展重写的方法,下面介绍在调用 Web 服务方法的整个过程中,Web 服务基础结构将于何时调用这些 SOAP 扩展方法。下列步骤假定 SOAP 扩展同时在客户端和服务器上运行。如果 SOAP 扩展未同时在客户端和服务器上运行,.NET Framework 将忽略与只在客户端或服务器上运行的 SOAP 扩展关联的步骤。

客户端准备请求消息

  1. 客户端调用代理类上的方法。

  2. 随即会在客户端上创建该 SOAP 扩展的一个新实例。

  3. 如果这是此 SOAP 扩展首次在客户端上通过此 Web 服务执行,则会对客户端上运行的 SOAP 扩展调用 GetInitializer 方法。

  4. 调用 Initialize 方法。

  5. 调用 ChainStream 方法。

  6. 调用将 SoapMessageStage 设置为 BeforeSerializeProcessMessage 方法。

  7. 客户端计算机上的 ASP.NET 将 Web 服务方法的参数序列化为 XML。

  8. 调用将 SoapMessageStage 设置为 AfterSerializeProcessMessage 方法。

  9. 客户端计算机上的 ASP.NET 通过网络将 SOAP 消息发送到承载该 Web 服务的 Web 服务器。

服务器端接收请求消息并准备响应

  1. Web 服务器上的 ASP.NET 接收该 SOAP 消息。

  2. 随即会在 Web 服务器上创建该 SOAP 扩展的一个新实例。

  3. 在 Web 服务器上,如果这是此 SOAP 扩展首次在服务器端通过此 Web 服务执行,则会对服务器上运行的 SOAP 扩展调用 GetInitializer 方法。

  4. 调用 Initialize 方法。

  5. 调用 ChainStream 方法。

  6. 调用将 SoapMessageStage 设置为 BeforeDeserializeProcessMessage 方法。

  7. ASP.NET 反序列化 XML 中的参数。

  8. 调用将 SoapMessageStage 设置为 AfterDeserializeProcessMessage 方法。

  9. 对于实现 Web 服务的类,ASP.NET 将为其创建一个新实例,同时调用 Web 服务方法并传入反序列化的参数。此对象驻留在充当 Web 服务器的计算机上。

  10. Web 服务方法将执行其代码,并最终设置返回值和所有输出参数。

  11. 调用将 SoapMessageStage 设置为 BeforeSerializeProcessMessage 方法。

  12. Web 服务器上的 ASP.NET 会将返回值和输出参数序列化为 XML。

  13. 调用将 SoapMessageStage 设置为 AfterSerializeProcessMessage 方法。

  14. ASP.NET 通过网络将 SOAP 响应消息发送回 Web 服务客户端。

客户端接收响应消息

  1. 客户端计算机上的 ASP.NET 接收该 SOAP 消息。

  2. 调用将 SoapMessageStage 设置为 BeforeDeserializeProcessMessage 方法。

  3. ASP.NET 将 XML 反序列化为返回值和任何输出参数。

  4. 调用将 SoapMessageStage 设置为 AfterDeserializeProcessMessage 方法。

  5. ASP.NET 将返回值和所有输出参数传递给代理类的实例。

  6. 客户端接收返回值和所有输出参数。

实现 SOAP 扩展

在客户端或服务器应用程序中运行 SOAP 扩展有两种方法。第一,您可以将应用程序配置为运行扩展。若要将 SOAP 扩展配置为对所有 Web 服务(特别是 vroot)的所有 Web 方法运行,请编辑 Web.config 文件中的 <soapExtensionTypes> 元素部分。下面的代码演示 type 特性值必须位于一行中,并且必须包括扩展的完全限定名称以及签名程序集的版本、区域性和公钥标记。

<configuration>
 <system.web>
    <webServices>
      <soapExtensionTypes>
        <add type="Contoso.MySoapExtension, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
priority="1" group="0"/>
        </soapExtensionTypes>
    </webServices>
  </system.web>
</configuration>

第二,您可以创建适用于 Web 服务方法的自定义特性。若要创建自定义特性,请创建一个从 SoapExtensionAttribute 派生的类。有关创建自定义特性的详细信息,请参见如何:实现 SOAP 扩展。有关创建自定义特性的更多信息,请参见“创建自定义特性”。

esw638yk.note(zh-cn,VS.100).gif注意:
实现 SOAP 扩展时,如果扩展使用 XmlTextReader 读取数据流,则可能会受到拒绝服务 (DOS) 攻击。若要避免这种攻击,一种方法是确保将 ProhibitDtd 属性设置为 true

优先级和优先级组

无论通过特性还是配置,都可以向 SOAP 扩展分配优先级。这样,在将多个 SOAP 扩展配置为与同一 XML Web services 方法一起运行时,将有助于确定执行的相对顺序。SOAP 扩展的优先级越高,其执行时间就越接近通过网络发送或收到 SOAP 消息的时间。SOAP 扩展可分为三个优先级组。在每个组中,各个成员用 priority 属性区分。priority 属性值越小,相对优先级就越高(0 表示优先级最高)。

SOAP 扩展的三个相对优先级组为:使用特性配置的 SOAP 扩展、在配置文件中通过将 group 设置为 01 指定的 SOAP 扩展。它们的优先顺序如下:

  • 优先级最高的组:通过在配置文件中将 group 设置为 0 配置的 SOAP 扩展。

  • 优先级居中的组:使用特性配置的 SOAP 扩展。

  • 优先级最低的组:通过在配置文件中将 group 设置为 1 配置的 SOAP 扩展。

下面的代码示例是一个配置文件,其中指定 Logger.LoggerExtension SOAP 扩展在相对优先级组 0 中运行,且优先级为 1

<configuration>
 <system.web>
   <webServices>
     <soapExtensionTypes>
      <add type="Logger.LoggerExtension,logger"
           priority="1"
           group="0" />
     </soapExtensionTypes>
    </webServices>
 </system.web>
</configuration>

另请参见

任务

如何:实现 SOAP 扩展

参考

SoapExtension
SoapExtensionAttribute
SoapMessageStage
LogicalMethodInfo

概念

使用 SOAP 扩展修改 SOAP 消息
XML Web services 生存期分析
生成 XML Web services 客户端

其他资源

Configuring Applications
使用 ASP.NET 的 XML Web services