HttpModule終极學習

来源:互联网 发布:扫描变文字软件 编辑:程序博客网 时间:2024/05/22 12:30

HttpModule終极學習

先說一下asp運行机制
當請求一個*.asp文件時,這個http request首先被inetinfo.exe進程截获,这个inetinfo.exe进程就是WWW服务进程,然后她会将这个请求转交给asp.dll进程,asp.dll进程就会解释执行这个asp叶面,然后将解释后的数据流返回给客户端浏览器。

当请求一个*.aspx文件的时候,同样的这个http request会被inetinfo.exe进程截获,她判断文件的后缀之后,将这个请求转交给ASPNET_ISAPI.dll,ASPNET_ISAPI.dll会通过一个被称为Http PipeLine的管道,将请求发送给ASPNET_WP.exe进程,当这个http request进入ASPNET_WP.exe进程之后,会通过HttpRuntime来处理这个请求,处理完毕将结果返回客户端。

当Http Request进入HttpRuntime之后,会继续进入到一个被称之为HttpApplication Factory的一个Container中,她会给出一个HttpApplication来处理传递进来的请求,这个请求会依次进入如下几个Container:HttpModule->HttpHandler Factory->HttpHandler。
当系统内部的HttpHandler的ProcessResquest方法处理完毕之后,整个Http Request就完成了,客户端也就得到相应的东东了。

整理后的流程如下:
HttpRequest-->inetinfo.exe-->ASPNET_ISAPI.dll-->Http Pipeline-->ASPNET_WP.exe-->HttpRuntime-->HttpApplication Factory-->HttpApplication-->HttpModule-->HttpHandler Factory-->HttpHandler-->HttpHandler.ProcessRequest()

其實這個流程也不完全正确.它們之間并不是完全的順序關系.較准确的流程如下:

http://www.cnblogs.com/images/cnblogs_com/stwyhm/HttpModule/HttpModuleLife.jpg
http://p.blog.csdn.net/images/p_blog_csdn_net/jilinxbz/图7.JPG


在一个http request在HttpModule传递过程中,会在某一个时刻(确切的说应当是事件)中将这个请求传递给HttpHandler的。这个事件就是ResolveRequestCache,在这个事件之后,HttpModule会建立一个HttpHandler的入口实例(做好准备了,:)),但是此时并没有将控制权交出,而是继续触发AcquireRequestState以及PreRequestHandlerExecute事件(如果你实现了的话)。看到了吗,最后一个事件的前缀是Pre,呵呵。这表明下一步就要进入HttpHandler了,的确如此,正如我们猜想的那样,在PreRequestHandlerExecute事件之后,HttpModule就会将控制权暂时交给HttpHandler,以便进行真正的http request处理工作。而在HttpHandler内部会执行ProcessRequest来处理请求。在HttpHandler处理完毕之后,会将控制权交还给HttpModule,HttpModule便会继续对处理完毕的http Request进行层层的转交动作,直到返回到客户端。


ASP.NET系统中默认的HttpModule有以下几个:
/*

這里的是另一版本,不知道怎么回事,不管它
System.Web.Caching.OutputCacheModule
System.Web.SessionState.SessionStateModule
System.Web.Security.WindowsAuthenticationModule
System.Web.Security.FormsAuthenticationModule
System.Web.Security.PassportAuthenticationModule
System.Web.Security.UrlAuthorizationModule
System.Web.Security.FileAuthorizationModule
*/

DefaultAuthenticationModule. 此筛选器确保 Authentication 对象出现在 HttpContext 对象中。
FileAuthorizationModule. 此筛选器验证远程用户是否拥有访问所请求的文件时所需的 Microsoft Windows NT? 权限。
FormsAuthenticationModule. 此筛选器使 ASP.NET 应用程序能够使用窗体验证。
PassportAuthenticationModule.此筛选器提供了包装 PassportAuthentication 服务以便进行 Passport 身份验证的包装器。
SessionStateModule. 此筛选器为应用程序提供会话状态服务。
UrlAuthorizationModule. 此筛选器提供基于 URL 的授权服务,以便允许或拒绝对指定 URL 进行访问。
WindowsAuthenticationModule. 此筛选器使 ASP.NET 应用程序能够使用 Microsoft Windows? 或 Internet 信息服务 (IIS) 的身份验证机制。


那么如何自定義HttpModule呢?
只需編寫一個類,并實現IHttpModule接口即可.這個接口有兩個方法(Init,Dispose)要實現.其中Dispose方法中通常不需要添加任何代碼.具体實現參見下例:
例1:
using System;
using System.Web;
namespace MyModule
{
 public class MyModule : IHttpModule
 {
  public void Init(HttpApplication application)
  {
   application.BeginRequest += (new
EventHandler(this.Application_BeginRequest));
   application.EndRequest += (new
EventHandler(this.Application_EndRequest));
  }
      private void Application_BeginRequest(Object source, EventArgs e)
  {
   HttpApplication Application = (HttpApplication)source;
            HttpResponse Response=Application.Context.Response;
   Response.Write("<h1>Beginning of Request</h1><hr>");
  }
      private void Application_EndRequest(Object source, EventArgs e)
  {
   HttpApplication application = (HttpApplication)source;
   HttpResponse Response=Application.Context.Response;
   Response.Write("<h1>End of Request</h1><hr>");
  }       
  public void Dispose()
  {
  }
 }
}
在自定義HttpModule中主要是通過對HttpApplication對象的一系列事件的處理来对HTTP处理管道施加影响,以下事件可以在HttpModule的Init方法中进行注册,包括如下:

下表显示了可以使用 ASP.NET 截取的、在处理请求期间产生的事件。所有事件都是按照发生的顺序列出的。

第一个列表显示了处理请求之前产生的事件。

BeginRequest. 此事件标志着这是一个新请求;每个请求都必须产生该事件。

AuthenticateRequest. 此事件标志着所配置的身份验证机制已经验证了请求。附加到此事件可向筛选器确保请求已通过身份验证。

AuthorizeRequest. 与 AuthenticateRequest 一样,此事件标志着现在请求在处理过程中又前进了一步,并且请求已经得到授权。

ResolveRequestCache. 输出缓存模块使用此事件来简化对已经缓存的请求所进行的处理。

AcquireRequestState. 此事件标志着应该获得各个请求状态。

PreRequestHandlerExecute. 此事件标志着请求处理程序将要执行。这是在调用此请求的 HTTP 处理程序之前您可以参与的最后一个事件。

下一个列表显示了处理请求之后产生的事件。这些事件是按照发生的顺序列出的:

PostRequestHandlerExecute. 此事件标志着 HTTP 处理程序已经完成了对请求的处理。

ReleaseRequestState. 此事件标志着应该存储请求状态,因为应用程序已经完成了对请求的处理。

UpdateRequestCache. 此事件标志着代码处理已完成,可以将文件添加到 ASP.NET 缓存中。

EndRequest. 此事件标志着已完成对请求的所有处理。这是应用程序结束时所调用的最后一个事件。

此外,以下三个请求处理前事件可以按不确定顺序引发:

PreSendRequestHeaders.此事件标志着 HTTP 头将要发送给客户端。因此可以在发送之前添加、删除或修改头信息。

PreSendRequestContent. 此事件标志着内容将要发送给客户端。这为发送之前修改内容提供了一个机会。

Error. 此事件标志着有未处理的异常。

 

其中部分事件同Global.asax中的事件相对应,对应关系如下:

HttpModule <---> Global.asax
BeginRequest <--->  Application_BeginRequest
AuthenticateRequest <--->  Application_AuthenticateRequest
...
EndRequest <--->  Application_EndRequest


接下來在web.config文件中注冊這個自定義的HttpModule
<configuration>
    <system.web>
        <httpModules>
            <add name=" MyModule " type=" MyModule, MyModule" />
        </httpModules>
    </system.web>
</configuration>
在系統中不是還有几個默认的HttpModule嗎,它們在哪里注冊的呀?因為web.config是從Machine.config繼承來的,所以默認的那几個HttpModule是在Machine.config中注冊的.


如果我們定義了多個HttpModuel,我們可以同時在這web.config中注冊.如果是這樣,那么它們的事件順序關系是怎樣的呢?它們与Global中的事件順序關系又是怎樣的呢?
如果你在web.config配置了两个HttpModule,分别是HttpModuleA,HttpModuleB,那么它們之間的關系如下:
Application_BeginRequest
HttpModuleA->BeginRequest
HttpModuleB->BeginRequest

Application_AuthenticateRequest
HttpModuleA->AuthenticateRequest
HttpModuleB->AuthenticateRequest

Application_AuthorizeRequest
HttpModuleA->AuthorizeRequest
HttpModuleB->AuthorizeRequest
...以此类推

應用
在HttpModule中可以定義那多事件,可是如何選擇注冊哪些事件呢?這要看你所要的功能是什么.
自定義HttpModule的用途,网上流行的做法是用來做權限管理,單點登陸和url重寫,以及在整站中加入廣告或通知等.當然還有其它用途,如本地化,錯誤處理,日志管理...具体可以參見DNN中的做法.

下面是一個權限實例:
1.暴露给客户端调用的权限校验类的定义如下:
public class RightChecker
{
 public static bool HasRight(User user,Module module)
 {
  //进行权限校验,
 }
}

2.利用HttpModule编写一个过滤器:
using System;
using System.Web;
namespace MyModule
{
 public class MyModule : IHttpModule
 {
  public void Init(HttpApplication application)
  {
 application. AcquireRequestState += (new
EventHandler(this.Application_AcquireRequestState));
  }
  private void Application_AcquireRequestState (Object source,
EventArgs e)
  {
   HttpApplication Application = (HttpApplication)source;
   User user=Application.Context.Sesseion["User"]  //获取User
   string url=Application.Context.Request.Path;
//获取客户访问的页面
   Module module= //根据url得到所在的模块
   If(!RightChecker.HasRight(user,module))
Application.Context.Server.Transfer("ErrorPage.aspx");
//如果没有权限,引导到错误处理的页面
  }
  public void Dispose()
  {
  }
 }
}
3.將這個HttpModule注冊.

 

參考文獻:
http://www.pcdog.com/edu/aspdotnet/2006/10/n150953.html
http://industry.ccidnet.com/art/1077/20040224/695231_1.html
http://www.cndw.com/tech/net/200202042598.asp
http://www.xmlasp.net/n521c12.aspx
http://donami.blog.163.com/blog/static/4200924920078132291186/
http://blog.csdn.net/fanweiwei/archive/2007/04/10/1558912.aspx
http://www.aspxboy.com/484/archive.aspx

 

原创粉丝点击