ASP.NET使用管道模型(PipleLines)处理HTTP请求

ASP.NET 使用管道模型( PipleLines )处理 HTTP 请求
                                       
 
   大多数人认为ASP.NET仅仅只是页面——使用模板来创建HTML页面然后返回给浏览器。但是这仅仅只是ASP.NET使用HTTP管道模型处理WEB程序很小的一方面。管道模型是类似于Web Services的一种在服务器端处理ASP.NET页面的框架技术。作为一名高级的ASP.NET的开发者,你必须清楚管道模型是如何工作的。这篇文章就是解释和阐述HTTP管道模型是如何处理HTTP请求的。
一、管道对象模型
在 System.Web的命名空间中处理HTTP的请求主要使用管道模型。一般的管道模型的结构如图-1。在管道模型开始运行前,HTTP的请求首先被传到HttpRuntime类的一个实例中,然后这个HttpRuntime的对象开始检查请求并找出这个请求被发送到的那个应用程序(在管道程序看来,一个虚拟目录就是一个应用程序)。然后管道模型就使用一个HttpApplicationFactory对象来找出或者创建一个HttpApplication对象来处理这个请求,一个HttpApplication可以包含一系列HTTP module对象(派生自IHttpModule接口)。HTTP modules作为一个过滤器可以在HTTP请求和响应信息穿过管道模型时检查和修改这些信息的内容。然后HttpApplication对象就使用HTTP handler factory来找出或产生一个HTTP handler对象。HTTP handlers是HTTP通信的最后一步,它主要用于处理请求信息(request)和响应信息(response)。注:HTTP handlers和 handler factory分别派生自IHttpHandler接口和IHttpHandlerFactory接口。
图-1
一个HttpApplication包括它的modules、handler在同一时刻只能处理一个Request请求。如果多重request请求同时到达一个相同的application时,多重HttpApplication对象将会被使用。
管道模型使用一个HttpContext对象去描述声明每一个成对的request/response信息。这个对象在HttpApplicaiton和handler之间来回传递。每一个module也能访问当前的HttpContext。HttpContext对象通过属性来描述声明HTTP的request和response信息(分别创建HttpRequest类和HttpResponse类的对象);同样,HttpContext对象也能通过属性来描述声明安全信息和每一个call、session和application。 -2展示了部分HttpContext类常用的属性。
ASP.NET的HTTP管道模型是可扩展的,你可以实现自己的HTTP module、handler以及handler factory。你也可以直接继承HttpApplication类。
 
 
 
属性名
描述
Application
每一个 application的request信息
Application Instance
正在处理 request请求的Application对象
Cache
每一个 application的缓存信息
Handler
正在处理 request请求的Handler对象
Items
每一个 request请求信息
Request
HTTP request 信息
Response
HTTP response 信息
Server
Utility functions
Session
Per-user cross-request state
User
User information
图 -2:HttpContext类的常用属性
 
二、管道处理模型
ASP.NET的HTTP管道程序运行在IIS上来接收传递到进程中的request请求(被完整地传送到其他的web服务器上)。当IIS接收到一个HTTP的request请求时,它首先会通过目标URL检查文件的扩展名,如果文件的名被可执行代码关联,IIS就会调用这些代码来处理request请求。文件的扩展名被映射成可执行代码存储在IIS的metabase标记中。当ASP.NET被安装后,它会通过一个动态链接库 aspnet_isapi.dll将各种不同的文件扩展名添加到 matabase标记中,包括.apx和.asmx。
当 IIS收到一个某一个页面文件发送的HTTP request请求时,它会调用aspnet_isapi.dll中的代码:使用一个命名管道将IIS服务器上的inetinfo.exe发送来的request请求转发到ASP.NET工作进程的一个实例:aspnet_wp.exe中。(在Windows Server 2003中, IIS 6.0kernel-mode模式的HTTP listener, 允许 request请求不通过inetinfo.exe而直接从操作系统转发到工作进程。)工作进程使用一个HttpRuntime类的实例来处理request请求。图-3 展示了完整的机制。
图 -3
HTTP管道程序在工作进程的实例中处理request请求。默认地,在某一时刻仅仅只能有一个工作进程工作(如果你的web服务器有多个CPU,你可以配置管道程序使用多个工作进程),这是一个在本地IIS上很重要的一个改变,它使用不同的工作进程主要为了隔离不同的application程序。同时管道程序的各个工作进程也完全地被AppDomain所隔离,你可以将AppDomain看作是进程中的一个子进程。管道程序向一个AppDomain中的所有虚拟目录发送HTTP request请求。换句话说,每一个虚拟目录被作为一个单独的应用程序对待。这还有另外一个本地IIS值得注意的改变就是允许多个虚拟目录成为同一个application的一部分。
 ASP.NET支持基于很多标准的循环工作进程,这些标准包括空闲时间、requests serviced的数量、requests队列的数量以及物理内存的耗费量。全局.NET配置文件和machine配置文件初始化这些数值(好象processModel的元素)。当一个aspnet_wp.exe的实例 crosses one of these thresholds, aspnet_isapi.dll会运行一个新的工作进程并开始发送request请求。旧的实例在它处理完request请求后会自动终止。循环工作进程会提升可靠性通过在这些进程耗尽资源之前杀死它们。
三、 HTTP Handlers
HTTP handlers 是一个继承自IHttpHandler接口的简单类,以下是该类的详细代码:
interface IHttpHandler
{
 // called to process request and generate response
 void ProcessRequest(HttpContext ctx);
 // called to see if handler can be pooled
 bool IsReuseable { get; }
}
Handlers也可以继承自IHttpAsyncHandler接口,如果想要它们支持异步调用
HttpApplicaiton对象会调用ProcessRequest方法,通过handler来处理当前的HTTP请求和产生response响应。在此期间IsReuseable属性会被访问为类测定hanlder是否可以被再使用。
图-4的代码实现了一个简单的可以重用的HTTP句柄,它可以响应所有的request请求并返回当前的时间在一个XML标记中。你也可以使用使用HttpContext对象的response属性来设置response信息的MIME属性从而输出自己的内容。
using System;
using System.Web;
 
namespace Pipeline
{
 
 public class TimeHandler : IHttpHandler
 {
    void ProcessRequest(HttpContext ctx)
    {
      ctx.Response.ContentType = "text/xml";
      ctx.Response.Write("<now>");
      ctx.Response.Write(
                   DateTime.Now.ToString());
      ctx.Response.Write("</now>");
    }
    bool IsReuseable { get { return true; } }
 }
}
图 -4:TimeHandler


 
 
当 HTTP handler类被实现时,它一定是被配置好的。配置会分为三个阶段:第一、你应该将编译好的代码放到ASP.NET工作进程能够找到的地方。一般地,已编译好的.NET文件(一般是dll文件)应该位于web服务器的虚拟目录下的bin文件夹中或位于全局编译缓存中(GAC)。
第二步:在 HTTP request请求到来时,你应该让HTTP的管道程序执行你的代码。你可以通过在你虚拟目录下的web.config文件中去添加<httpHandlers>标签。如下:
<configuration>
 <system.web>
 <httpHandlers>
   <add verb="GET" path="*.time"
     type="Pipeline.TimeHandler,
     Pipeline"
   />
 </httpHandlers>
 </system.web>
</configuration>
   以上的代码可以作为附加的信息添加到 .config的配置文件中。例如,这个web.config文件会告诉asp.net的HTTP管道程序处理所有.time文件的GET请求通过调用编译文件中的Pipeline.TimeHandler类。
最后,这些 .time文件的request请求会被IIS转发到aspnet_isapi.dll,以便这些请求可以被管道程序第一时间处理。而且这些request请求也会在IIS的metabase中添加一个新的文件mapping映射。不过还有更简单的方式,就是直接使用IIS管理台将虚拟目录的文件扩展名映射到Application的配置对话框中。如图-5

图 -5
 
 
除了实现已有的客户端handler外,你也可以写自己的handler factoriey。一个handler factoriey就是一个实现了IHttpHandlerFactory的类。Handler factiory的配置方法和普通handlers一样,唯一不同的是原先web.config文件中的handler类都将被factory类所代替。
 
四、标准Handlers
    一些高级的 ASP.NET技术,例如pages和Web Services都是通过顶层HTTP handler直接创建的。以下是通过.config文件来配置<httpHandlers>部分:
<httpHandlers> entries:
<httpHandlers>
 <add verb="*" path="*.ashx"
 type="System.Web.UI.SimpleHandlerFactory"
 />
 <add verb="*" path="*.aspx"
    type="System.Web.UI.PageHandlerFactory"
   />
   <add verb="*" path="*.asmx"
    type="System.Web.Services.Protocols.
    WebServiceHandlerFactory ... "
   />
 </httpHandlers>
    第一个实体映射扩展名为 .ashx的文件到SimpleHandlerFactory类,使得一个HTTP handler factory知道如何从.ashx源文件中安装、编译和执行一个IHttpHandler。然后结果对象就可以被HTTP管道程序直接使用。
    图-6展示了使用.ashx文件重写的一个TimeHandler例子。@WebHandler部分告诉SimpleHandlerFactory Http handler类的名字在源代码编译后。这么做最大的好处就在它的配置非常简单:你只需要将所有的.ashx文件拷贝到虚拟目录下,而不需要再创建或修改web.config文件或在.NET安装完后再更新IIS。
<%@ WebHandler language="C#"
    class="Pipeline.TimeHandler" %>
 
using System;
using System.Web;
 
namespace Pipeline
{
 
 public class TimeHandler : IHttpHandler
 {
    void ProcessRequest(HttpContext ctx)
    {
      // set response message MIME type
      ctx.Response.ContentType = "text/xml";
      // write response message body
      ctx.Response.Write("<now>");
      ctx.Response.Write(
                   DateTime.Now.ToString());
      ctx.Response.Write("</now>");
    }
    bool IsReuseable { get { return true; } }
 }
}
图 -6

第二个 <httpHandlers>部分的实体将.aspx文件扩展名映射到PageHandlerFactory类,主要为了让HTTP handler factory知道如何将.aspx的源代码编译成一个System.Web.UI.Page-derived类。这个Page类实现了IHttpHandler借口,因此最终对象可以被HTTP管道程序直接使用。
第三个实体将 .asmx的扩展名映射到WebServiceHandlerFactory类,这么做主要为了让一个HTTP handler factory知道如何将一个.asmx文件中的源代码编译并实例化。然后它会绑定一个标准的HTTP handler(默认的为SyncSessionlessHandler)实例并使用反射机制将SOAP信息转化成方法的调用参数。最后,最终对象就可以被HTTP管道程序直接使用了。
  
这里需要值得注意的是 PageHandlerFactory、WebServiceHandlerFactory和SimpleHandlerFactory类并不能在每一个request请求上都编译.aspx、.asmx和.ashx文件。作为替代,这些编译好的代码会被缓存在ASP.NET安装目录下的临时文件中。并且当源代码改变时,这些代码仅仅只会被编译一次。

五、 HTTP Modules
    HTTP handlers是HTTP通信的最终部分。Handler类的实例专门用来接收HTTP请求并产生response响应。HTTP modules作为过滤器在request和response信息穿过管道程序时处理它们(可以是检查并修改这些信息的内容)。管道程序可以用这些HTTP modules特别安全地实现自己的底层处理程序。
HTTP modules 是实现IHttpModule接口的简单类:
interface IHttpModule
{
 // called to attach module to app events
 void Init(HttpApplication app);
 // called to clean up
 void Dispose()
}
当 module被第一次创建时,Init方法会被HttpApplication对象调用,它可以通过HttpApplication对象将一个或多个事件handlers绑定到事件上。
图 -7的代码展示了一个HTTP module如何处理HttpApplication对象的BeginRequest和EndRequest事件。在这个例子中,Init方法使用了常见的.NET技术将module的OnBeginRequst和OnEndRequest作为事件句柄绑定到HttpApplication对象上。 OnBeginRequest主要作用是获取存储当前时间并将时间存放到变量start中。而OnEndRequest主要作用是计算OnBeginRequest和OnEndRequest之间的运行时间差并将这段时间添加到客户端HTTP header中。
 
OnEndRequest方法的最大优势在于第一个参数实际上传递的module绑定的HttpApplication对象。并且当前的信息会做为一个HttpApplication对象的属性(Http-Context)被OnEndRequest方法使用。
using System;
using System.Web;
 
namespace Pipeline
{
 
 public class ElapsedTimeModule : IHttpModule
 {
    DateTime start;
    public void Init(HttpApplication app)
    {
      // register for pipeline events
      app.BeginRequest +=
          new EventHandler(this.OnBeginRequest);
      app.EndRequest +=
          new EventHandler(this.OnEndRequest);
    }
    public void Dispose() {}
 
    public void OnBeginRequest(object o,
                               EventArgs args)
    {
      // record time when request started
      start = DateTime.Now;
    }
 
    public void OnEndRequest(object o,
                             EventArgs args)
    {
      // measure elapsed time
      TimeSpan elapsed =
              DateTime.Now - start;
 
      // get access to app and context
      HttpApplication app =
              (HttpApplication) o;
      HttpContext ctx = app.Context;
 
      // add custom header to HTTP response
      ctx.Response.AppendHeader(
                   "ElapsedTime",
                   elapsed.ToString());
    }
 }
}
图 -7
在一个 HTTP module类被实现和使用之间,必须对它做一定的配置。配置的步骤包括两步。首先你应该将编译好的module代码放到web服务器上的站点目录下的bin文件夹中以至于ASP.NET的工作进程能够找到它。
    然后你应该在你的web.config文件中添加<httpModules>部分,如下:
<configuration>
 <system.web>
 <httpModules>
   <add
    name="Elapsed"
    type="Pipeline.ElapsedTimeModule, Pipeline"
   />
 </httpModules>
 </system.web>
</configuration>
   这个例子中, web.config文件会告诉ASP.NET的HTTP管道程序将Pipeline.ElapsedTimeModule绑定到每一个HttpApplication对象用来处理这个虚拟目录下的service请求。
 
 
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值