网络安全 频道

ASP.NET Web服务如何工作?

摘要:本文讲解微软ASP.NET Web服务方法(WebMethod)是如何提供高效率的建立Web服务的途径的。WebMethod可以把传统的微软.NET方法暴露为Web服务操作,支持HTTP、XML、XML Schema、SOAP和WSDL。WebMethod(.asmx)处理处理程序能自动地把输入的SOAP消息传递给适当的方法,并自动地把输入的XML元素串行化为相应的.NET对象。

  介绍

  目前在微软.NET中实现基于HTTP的Web服务有两种根本不同的途径。最底层的技术是编写一个插入.NET HTTP管道的自定义IHttpHandler类。这种途径要求你使用System.Web API来处理输入的HTTP消息,使用System.Xml API处理HTTP体中的SOAP封装。编写自定义处理程序要求你手工建立正确描述实现的WSDL文档。严格执行所有的这些操作要求你非常了解XML、XSD、SOAP和WSDL规范,但是这对于大多数开发者来说很困难。

  实现Web服务的效率更高的途径是使用微软ASP.NET WebMethods框架组件。ASP.NET为.asmx终结点(称为WebServiceHandler)发布了一个特定的IHttpHandler类,它提供必要的XML、XSD、SOAP和WSDL功能的范本文件。因为WebMethods框架组件把你从下层XML技术的复杂性中解放了出来,你能够快速聚焦于手头的业务问题。

  图1:灵活性和生产率之间的折衷

  在实现技术之间作出选择形成了图1中所示的灵活性和生产率之间的折衷。编写自定义的IhttpHandler给了你无限大的灵活性,但是要花费你很长时间编写、测试和调试代码。WebMethods框架组件使建立自己的Web服务和快速运行变得很容易,但是很明显你要受到该框架组件界限的限制。但是,在WebMethods框架组件不能提供你完全需要的信息的情况下,可以通过添加自己的附加功能来扩展该框架组件。

  通常,除非你已经掌握了XML、XSD、SOAP和WSDL并且原意承担直接处理它们的负担,最好不要专注于Web服务所需要的WebMethods框架组件。它提供了大多数Web服务端点(endpoints)所需要的基本服务,以及能把框架组件进行"弯曲"来适合你的精确的需要的一些有趣的可扩充能力。本文是基于这种假定讨论WebMethods如何工作的内部信息。如果你不太了解XML Schema和SOAP,可以参阅Understanding XML Schema和Understanding SOAP。

  WebMethods框架组件

  WebMethods框架组件循环地把SOAP消息映射到.NET类中的方法。这种功能的实现首先需要把你的方法注解为System.Web.Services名字空间中的[WebMethod]属性。例如,下面的.NET类包含四个方法,其中两个使用[WebMethod]属性注解了:

using System.Web.Services;

public class MathService
{
   [WebMethod]
   public double Add(double x, double y) {
      return x + y;
   }
   [WebMethod]
   public double Subtract(double x, double y) {
      return x - y;
   }
   public double Multiply(double x, double y) {
      return x * y;
   }
   public double Divide(double x, double y) {
      return x / y;
   }
}


  为了在WebMethods框架组件重使用这个类,你需要把这个类编译为一个部件(assembly)并把它复制到虚拟目录的bin目录中。在这个例子中,Add和Subtract方法可以被暴露作为Web服务操作,但是Multiply和Divide却不能(因为它们没有使用[WebMethod]标记)。

  你可以通过一个.asmx端点(endpoint)把Add和Subtract暴露为Web服务操作。为了实现这个功能,建立一个名为Math.asmx的包含下面的简单声明的新文本文件,并把它放到包含该部件的虚拟目录中(注意:它自己进入虚拟目录而不是子目录bin中):

<%@ WebService class="MathService"%>


  这个声明告诉.asmx处理程序使用哪个类检查WebMethods,并且该处理程序自动处理其它的信息。例如,假定虚拟目录叫作"math"并且它包含了Math.asmx,并且bin子目录包含了该部件,那么浏览http://localhost/math/math.asmx将导致.asmx处理程序生成图2所示的文档页面。

  这与.asmx处理程序如何工作有较大的变化。.asmx文件通常只包含通过名字引用Web服务类(如上所示)的WebService声明。因此,在这种情况下,该部件必须已经被编译好、配置到了虚拟目录的bin目录中。.asmx处理程序也提供.asmx文件中源代码的just-in-time(实时)编译。例如,下面的文件(叫作Mathjit.asmx)包含了WebService声明和被引用类的源代码。

<@% WebService class="MathServiceJit" language="C#"%>

using System.Web.Services;

public class MathServiceJit
{
   [WebMethod]
   public double Add(double x, double y) {
      return x + y;
   }
   [WebMethod]
   public double Subtract(double x, double y) {
      return x - y;
   }
   public double Multiply(double x, double y) {
      return x * y;
   }
   public double Divide(double x, double y) {
      return x / y;
   }
}


  第一次通过HTTP访问这个文件时,.asmx处理程序编译源代码并把部件配置到正确的位置。注意WebService声明必须提供语言,这样.asmx处理程序才能在运行时选择正确的编译器。这种方法的一个明显的问题是直到你第一次访问该文件时才会发现编译错误。

  图2:MathService文档

  当你使用Visual Studio .NET建立一个新的Web服务项目时,它通常使用"双文件"技术,把源文件与引用它的.asmx文件分开。集成开发环境(IDE)隐藏了这些文件,但是你可以点击"解决方案浏览器"工具条上的Show All Files(显示所有文件),你会发现项目中的每个Web服务类都有两个文件。实际上,Visual Studio .NET并不支持.asmx文件的高亮度提醒或IntelliSense。有了Web项目后,Visual Studio .NET也处理建立虚拟目录并自动把部件编译到虚拟目录的bin目录中。

  在深入分析.asmx处理程序如何工作前,我们先简短讨论一下来自IIS的消息如何分派到用于处理的.asmx处理程序中。当输入的HTTP消息到达80端口时,IIS使用自己的元数据库(metabase)的信息来找出使用哪一个ISAPI DLL来处理这个消息。.NET安装程序把.asmx扩展映射到Aspnet_isapi.dll,如图3所示。

  图3:.asmx 的IIS应用程序映射

  Aspnet_isapi.dll是.NET框架组件提供的一个标准的ISAPI扩充,它简单地把HTTP请求转发到单独的叫作Aspnet_wp.exe的工作进程中。Aspnet_wp.exe寄宿了通用语言运行时和.NET HTTP管道。一旦消息进入.NET HTTP管道,管道就查询配置文件,看应该使用哪一个IhttpHandler类处理给定的扩充。如果你查看Machine.config文件,你会发现它包含了.asm文件的一个httpHandler映射,如下所示:

<configuration>
  <system.web>
    <httpHandlers>  
        <add verb="*" path="*.asmx"
type="System.Web.Services.Protocols.WebServiceHandlerFactory, 
System.Web.Services, Version=1.0.3300.0, Culture=neutral, 
PublicKeyToken=b03f5f7f11d50a3a" validate="false"/>
...


  因此当某个目标为.asmx文件的消息进入.NET HTTP管道时,该管道调用WebServiceHandlerFactory类来实例化用于处理这个请求的新的WebServiceHandler对象。WebServiceHandler对象打开物理的.asmx文件以决定包含WebMethods的类的名称。

  一旦.asmx处理程序被.NET HTTP管道调用,它就开始处理XML、XSD、SOAP和WSDL进程。.asmx处理程序提供的功能可以分为三个部分:1)消息发送;2)把XML映射到对象;3)自动化WSDL和文档生成。下面讲详细讲解每一部分。

  消息发送

  当HTTP管道调用.asmx处理程序时,它通过查看.asmx文件中的WebService声明来找出使用哪个.NET类来检查。接着它查看输入的HTTP消息的信息以正确地决定调用被引用类地哪个方法。为了调用前面的例子中显示的Add操作,输入的HTTP消息必须有类似下面的信息:

POST /math/math.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/Add"

<soap:Envelope 
  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
>
  <soap:Body>
    <Add xmlns="http://tempuri.org/">
      <x>33</x>
      <y>66</y>
    </Add>
  </soap:Body>
</soap:Envelope>


  在输入的HTTP消息中的确有两部分信息可以用于找出调用类中的哪个方法:SOAPAction头部或者请求的元素名称(例如soap:Body元素内的元素名称)。在这种情况下,任何一个都表明了发送者希望调用的方法的名称。

  默认情况下.asmx处理程序使用SOAPAction头部的值来执行消息发送。因此,.asmx 处理程序查看消息中的SOAPAction头部,接着使用.NET反射(reflection)检查被引用类中的方法。它只考虑使用[WebMethod]标志标记的方法,但是它通过查看每个方法的SOAPAction值来正确地决定调用哪个方法。因为我们没有在自己的类的方法中明确指定SOAPAction的值,.asmx处理程序就假定SOAPAction的值是Web服务的名字空间后面跟上方法名称的组合。因为我们也没有指定名字空间,处理程序就把http://tempuri.org作为默认值。因此Add方法的默认的SOAPAction值是http://tempuri.org/Add。

  你可以使用[WebService]标志作为类的注解来自定义Web服务的名字空间,使用下面所说明的[SoapDocumentMethod]标志作为WebMethods的注解来指定SOAPAction的值:

using System.Web.Services;
using System.Web.Services.Protocols;

[WebService(Namespace="http://example.org/math")]
public class MathService
{
   [WebMethod]
   public double Add(double x, double y) {
      return x + y;
   }
   [WebMethod]
   [SoapDocumentMethod(Action="urn:math:subtract")]
   public double Subtract(double x, double y) {
      return x - y;
   }
   ...
}


  现在.asmx处理程序认为Add 方法的SOAPAction的值为http://example.org/math/Add(使用默认的启发式),Subtract方法的为urn:math:subtract(因为我们明确地定义了这个值)。例如,下面的HTTP请求消息调用Subtract操作:

POST /math/math.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "urn:math:subtract"

<soap:Envelope 
  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
>
  <soap:Body>
    <Subtract xmlns="http://example.org/math">
      <x>33</x>
      <y>66</y>
    </Subtract>
  </soap:Body>
</soap:Envelope>

0
相关文章