ASP.NET 管道

学习于:http://www.cnblogs.com/fish-li/archive/2011/09/05/2168073.html

ASP.NET管道中的事件处理采用了观察者模式,"观察者模式定义了对象之间的一种联系,使得当一个对象改变状态时,所有其它的对象都可以相应地被通知到"。在这个设计模式中,观察者就是许多HttpModule对象,被观察的对象就是每个"请求",它的状态是由HttpApplication 控制,用于描述当前请求的处理阶段,HttpApplication会根据一个特定的顺序修改这个状态,并在每个状态改变后引发相应的事件。 Asp.net会为每个请求分配一个HttpApplication对象来引发这些事件,因此可以让一大批观察者了解每个请求的状态, 每个观察者也可以在感兴趣的时候修改请求的一些数据。

MSDN【IIS 5.0 和 6.0 的ASP.NET应用程序生命周期概述】

在处理该请求时将由 HttpApplication 类执行以下事件。 希望扩展 HttpApplication 类的开发人员尤其需要注意这些事件。

1. 对请求进行验证,将检查浏览器发送的信息,并确定其是否包含潜在恶意标记。 有关更多信息,请参见 ValidateRequest 和脚本侵入概述。
2. 如果已在 Web.config 文件的 UrlMappingsSection 节中配置了任何 URL,则执行 URL 映射。
3. 引发 BeginRequest 事件。
4. 引发 AuthenticateRequest 事件。
5. 引发 PostAuthenticateRequest 事件。
6. 引发 AuthorizeRequest 事件。
7. 引发 PostAuthorizeRequest 事件。
8. 引发 ResolveRequestCache 事件。
9. 引发 PostResolveRequestCache 事件。
10. 根据所请求资源的文件扩展名(在应用程序的配置文件中映射),选择实现 IHttpHandler 的类,对请求进行处理。 如果该请求针对从 Page 类派生的对象(页),并且需要对该页进行编译,则 ASP.NET 会在创建该页的实例之前对其进行编译。
11. 引发 PostMapRequestHandler 事件。
12. 引发 AcquireRequestState 事件。
13. 引发 PostAcquireRequestState 事件。
14. 引发 PreRequestHandlerExecute 事件。
15. 为该请求调用合适的 IHttpHandler 类的 ProcessRequest 方法(或异步版 IHttpAsyncHandler.BeginProcessRequest)。 例如,如果该请求针对某页,则当前的页实例将处理该请求。 
16. 引发 PostRequestHandlerExecute 事件。
17. 引发 ReleaseRequestState 事件。
18. 引发 PostReleaseRequestState 事件。
19. 如果定义了 Filter 属性,则执行响应筛选。
20. 引发 UpdateRequestCache 事件。
21. 引发 PostUpdateRequestCache 事件。
22. 引发 EndRequest 事件。
23. 引发 PreSendRequestHeaders 事件。
24. 引发 PreSendRequestContent 事件。

如果是IIS7,第10个事件也就是MapRequestHandler事件,而且在EndRequest 事件前,还增加了另二个事件:LogRequest 和 PostLogRequest 事件。
只有当应用程序在 IIS 7.0 集成模式下运行,并且与 .NET Framework 3.0 或更高版本一起运行时,才会支持 MapRequestHandler、LogRequest 和 PostLogRequest 事件。

补充:从BeginRequest开始的事件,并不是每个事件都会被触发,因为在整个处理过程中,随时可以调用Response.End() 或者有未处理的异常发生而提前结束整个过程。在那些"知名"的事件中,也只有EndRequest事件是肯定会触发的, (部分Module的)BeginRequest有可能也不会被触发。

小结:
1. 每个请求都将会映射到一个HttpHandler,通常也是处理请求的主要对象。
2. HttpModule可以任意订阅这些事件,在事件处理器中也可以参与修改请求的操作。
3. 绝大多数的的请求都在【第10步】被映射到一个HttpHandler, 然后在【第15步】中执行处理过程

HttpHandler
HttpHandler通常是处理请求的核心对象。绝大多数的的请求都在【第10步】被映射到一个HttpHandler, 然后在【第15步】中执行处理过程,因此也常把这类对象称为处理器或者处理程序。我们熟知的Page就是一个处理器, 一个ashx文件也是一个处理器,不过ashx显示得更原始

通常,我们需要新的HttpHandler,创建一个ashx文件就可以了。 但也可以创建自己的HttpHandler,或者要将一类【特殊的路径/扩展名】交给某个处理器来处理, 那么就需要我们在web.config中注册那个处理器。

注意:如果是【特殊的扩展名】可能还需要在IIS中注册,原因很简单:IIS不将请求交给Asp.net,我们的代码根本没机会运行!

可以在web.config中注册一个自定义的处理器:

<httpHandlers>
      <add verb="*" path="*/Test.htm" type="WebApplication1.App_Code.HtmlHandler,WebApplication1"/>
</httpHandlers>

//当浏览器发起一个对Test.htm请求时,该请求会被路由到WebApplication1.App_Code下的HtmlHandler处理程序进行处理

让HttpModule工作也需要在web.config中注册:
<httpModules>
    <add name="TestModule" type="MySimpleServiceFramework.DuplexGzipModule"/>
</httpModules>

HttpModule的加载方式
Asp.net会为每个请求分配一个HttpApplication对象【意味着将会有多个HttpApplication对象】,在每个HttpApplication对象的初始化操作中,它会加载所有在web.config中注册的HttpModule。

Accept-Encoding
只是告诉服务端:客户端能接受什么样的编码,并不能表示某次请求体的内容是压缩过的

看不见的性能问题
对于每个Asp.net请求,每个HttpModule都会在它们所订阅的事件中去执行一些操作逻辑。这些操作逻辑或许对一些请求是无意义的,但仍会执行。 因此,计算机将会白白浪费一些资源去执行一些无意义的代码。
针对这种情形,解决办法如下:
1. 去掉不需要的HttpModule
2. 在每个HttpModule的事件处理器中,首先要确定是不是自己所需要处理的请求。对一些不相关的请求,应该立即退出。
在我们创建一个Asp.net项目时,如果不做任何修改,微软已经为我们加载了好多HttpModule 。
protected void Page_Load(object sender, EventArgs e)
{
    HttpApplication app = HttpContext.Current.ApplicationInstance;       
    StringBuilder sb = new StringBuilder();
    foreach( string module in app.Modules.AllKeys )
        sb.AppendFormat(module).Append("<br />");
    Response.Write(sb.ToString());
}
//输出结果:总共有14个HttpModule
可以在web.config将不需要的Module移除,如:
<httpModules>
    <remove name="Session"/>
    <remove name="RoleManager"/>
</httpModules>

原文地址:https://www.cnblogs.com/notebook2011/p/2860322.html