HttpRuntime打交道的是http协议跟IIS层面的东西,HttpApplication则具体到应用程序这一级别(也就是一个网站,这个跟web.config关系是基本一一对应的,像Module跟Handler的信息都是在这里定义),此时会生成相应的HttpContext(上下文信息,包括Request,Response等),在HttpApplication路由到具体的HttpHandler处理之时,HttpApplication的各个事件会被触发,而HttpModule则通过相应的事件如BeginRequest等来处理一些额外的事情,如UrlRewrite,缓存,安全验证等
管线(Pipeline)这个词也是很有点意思,这个词也形象地说明了每个Asp.net请求的处理过程: 请求是在一个管道中,要经过一系列的过程点,这些过程点连接起来也就形成一条线。 以上是我对于这个词的理解,如果有误,恳请给予指正。 这些一系列的过程点,其实就是由HttpApplication引发的一系列事件,通常可以由HttpModule来订阅, 也可以在Global.asax中订阅,这一系列的事件也就构成了一次请求的生命周期。
观察者模式:观察者模式定义了对象之间的一种联系,使得当一个对象改变状态时,其它对象会被相应的通知到。
Asp.net的管线设计正是采用了这种方式, 在这个设计模式中,观察者就是许多HttpModule对象,被观察的对象就是每一个请求,它的状态由HttpApplication控制,用于描述当前请求的处理阶段,
HttpApplication会根据一个特定的顺序修改这个状态,并在每个状态改变后引发相应的事件。 Asp.net会为每个请求分配一个HttpApplication对象来引发这些事件,因此可以让一大批观察者了解每个请求的状态, 每个观察者也可以在感兴趣的时候修改请求的一些数据。 这些与请求相关的数据的也就是HttpRequest, HttpResponse。
在处理该请求时将由 HttpApplication 类执行以下事件。 希望扩展 HttpApplication 类的开发人员尤其需要注意这些事件。
. 对请求进行验证,将检查浏览器发送的信息,并确定其是否包含潜在恶意标记。 有关更多信息,请参见 ValidateRequest 和脚本侵入概述。
. 如果已在 Web.config 文件的 UrlMappingsSection 节中配置了任何 URL,则执行 URL 映射。
. 引发 BeginRequest 事件。
. 引发 AuthenticateRequest 事件。
. 引发 PostAuthenticateRequest 事件。
. 引发 AuthorizeRequest 事件。
. 引发 PostAuthorizeRequest 事件。
. 引发 ResolveRequestCache 事件。
. 引发 PostResolveRequestCache 事件。
. 根据所请求资源的文件扩展名(在应用程序的配置文件中映射),选择实现 IHttpHandler 的类,对请求进行处理。 如果该请求针对从 Page 类派生的对象(页),并且需要对该页进行编译,则 ASP.NET 会在创建该页的实例之前对其进行编译。
. 引发 PostMapRequestHandler 事件。
. 引发 AcquireRequestState 事件。
. 引发 PostAcquireRequestState 事件。
. 引发 PreRequestHandlerExecute 事件。
. 为该请求调用合适的 IHttpHandler 类的 ProcessRequest 方法(或异步版 IHttpAsyncHandler.BeginProcessRequest)。 例如,如果该请求针对某页,则当前的页实例将处理该请求。
. 引发 PostRequestHandlerExecute 事件。
. 引发 ReleaseRequestState 事件。
. 引发 PostReleaseRequestState 事件。
. 如果定义了 Filter 属性,则执行响应筛选。
. 引发 UpdateRequestCache 事件。
. 引发 PostUpdateRequestCache 事件。
. 引发 EndRequest 事件。
. 引发 PreSendRequestHeaders 事件。
. 引发 PreSendRequestContent 事件。
对于这些管道事件
1.每个请求都将会映射到一个HttpHandler,通常也是处理请求的主要对象。
2.HttpModule可以任意订阅这些事件,在事件处理器中也可以参与修改请求的操作。
HttpHandler
HttpHandler通常是处理请求的核心对象。绝大多数的的请求都在【第10步】被映射到一个HttpHandler, 然后在【第15步】中执行处理过程,因此也常把这类对象称为处理器或者处理程序。我们熟知的Page就是一个处理器, 一个ashx文件也是一个处理器。
// 定义 ASP.NET 为使用自定义 HTTP 处理程序同步处理 HTTP Web 请求而实现的协定。
public interface IHttpHandler
{
// 获取一个值,该值指示其他请求是否可以使用 System.Web.IHttpHandler 实例。
//
// 返回结果:
// 如果 System.Web.IHttpHandler 实例可再次使用,则为 true;否则为 false。
bool IsReusable { get; } // 通过实现 System.Web.IHttpHandler 接口的自定义 HttpHandler 启用 HTTP Web 请求的处理。
void ProcessRequest(HttpContext context);
}
我们可以采用以下方式在web.config中注册一个自定义的处理器:
<httpHandlers>
<add path="/MyService.axd" verb="*" validate="false" type="MySimpleServiceFramework.MyServiceHandler"/>
</httpHandlers>
HttpModule
前面我已经提到过HttpModule的工作方式:订阅管线事件,并在事件处理器中执行所需的相关操作。
这个描述看起来很平淡,但是,它的工作方式给了它无限强大的处理能力。
它的无限强大的处理能力来源于可以订阅管线事件,因此,它有能力可以在许多阶段修改请求, 这些修改最终可能会影响请求的处理。
前面我说过:“HttpHandler是处理请求的主要对象”,但HttpModule却可以随意指定将某个请求交给某个处理器来执行!
甚至,HttpModule也可以直接处理请求,完全不给HttpHandler工作的机会!
public interface IHttpModule
{
void Dispose(); void Init(HttpApplication app);
}
在这二个方法中,第一个方法通常可以保持为空。最重要的方法就是Init,它给了HttpModule能订阅管线事件的机会, 然后在相应的事件处理中,我们就可以执行它的具体操作了。
<httpModules>
<add name="DuplexGzipModule" type="MySimpleServiceFramework.DuplexGzipModule"/>
</httpModules>
HttpModule的加载方式:ASP.NET会为每个请求分配一个HttpApplication对象,在每个HttpApplication对象的初始化操作中,它会加载所有在web.config中注册的HttpModule。由于Asp.net并不是只创建一个HttpApplication对象,而是多个HttpApplication对象, 因此每个HttpModule的Init事件是有可能被多次调用的。