MSDN文章:HttpModules [自己翻译]

??????? ASP.NET中一个有用的特性是HTTP管道的扩展性,所谓HTTP管道指的是从客户端到服务器端所经过的路径。这个月我将给大家展示一下HTTP Modules(模块)。我们可以用HTTP Modules扩展ASP.NET应用程序---也就是为我们的应用程序添加预处理和善后处理,然后由新的应用程序来处理每个到达的请求。举例来说,如果你想为你的应用程序添加自定义的认证,最有用的技术就是截取到达的客户端的请求,然后在自定义的HTTP module,下面我们就以HTTP管道开始我们的介绍。


HTTP管道

????? 要搞懂ASPNET中的HTTP module,你需要清楚HTTP管道如何工作。当一个HTTP请求通过80端口(HTTP常用端口,HTTPS和验证的sockets端口常用443端口)到达服务器,而在真正由你的应用程序处理之前,该请求会通过组成HTTP管道的一系列的过程。
????? Microsoft® Internet Information Services (IIS) 是一系列环节当中的第一环。虽然ASPNET有自己的对象模型、进程隔离机制、基于.NET Framework类的会话状态管理机制,IIS仍然被用来把请求传递到ASPNET运行时。IIS将ASPNET映射到ASPNET_ISAPI.DLL,它是一个由ASPNET提供的ISAPI扩展。ASPNET_ISAPI.DLL的功能是将请求传递到ASPNET工作者进程ASPNET_WP.EXE。这部分工作完成之后,该请求就被包装到HttpContext类的一个实例当中,接着通过管道经过许多ASPNET类。HttpContext 类包括很多成员,比如响应、请求,也包括你可能想知道的于请求有关的安全信息。
???????接下来该请求被传送到一个HttpApplication实例。这个步骤对于获得应用程序范围内的方法、数据和事件是很有用处的。由于这个类(HttpApplication)对于设置HTTPmoduls是很关键的,我将深入的来介绍一下HttpApplication。
?????? HttpApplication对象接受到请求之后,将它传递过一个或几个HttpModule对象。有许多系统级别的HTTP模块提供从状态管理认证到输出缓存的服务。截取请求的模块的数量是由机器级别的machine.config和对应应用同程序的web.config文件来设定。在ASP中提供预处理和善后处理比较经典的做法是在ISAPI过滤器中完成。这就表明,ASP HTTP模块编写时更直接更简单。

?????? 这一系列环节中最后一个环节是HttpHandler。如果你用过一段时间的ASPNET,你应该对System.Web.UI.Page 类比较熟悉。Page类是HttpHander的一个实例,它实现了IHttpHandler接口。实现IHttpHandler接口的类可以通过这个接口的ProcessRequest方法勾入(HOOK)HTTP管道和服务请求。

Figure 1 HTTP Request

Figure 1 HTTP Request

每个请求到来时,如果发现请求的URI指向一个ASP.NET扩展名的文件,ASP.NET会在web.config文件当中寻找与这个扩展名相关的实现了IhttpHandler接口的类。如果你在你的web.config文件当中没有做任何改变,当浏览到一个ASPX文件时,ASP.NET就会根据System.Web.UI.Page创建一个处理程序。你可以通过设置web.config文件来将单独的HTTP处理程序映射到各自相应的URI。图1表示了一个HTTP请求通过HTTP管道时经过的过程。与HttpModule相关的类包括:BeginRequest, AuthenticateRequest, AuthorizeRequest等。ASP.NET HTTP Modules

一个HTTP module其实就是一个实现了System.Web.IhttpModule接口的类。

public interface IHttpModule
{
? void Dispose();
? void Init(HttpApplication context);
}

当一个HttpModule挂接到管道时(通过在web.config文件中的设定的入口),ASP.NET运行时调用此模块的InitDispose方法。当模块将自己附加到HttpApplication对象时调用Init方法,而当模块取消与HttpApplication 的联系时调用Dispose方法。InitDispose方法表示了模块挂接到HttpApplication所暴露的一系列事件。这些事件包括请求开始、请求结束、请求认证等等。注意一下传递给Init方法的HttpApplication类型的参数。一般来说,Init方法接管HttpApplication对象并将事件处理程序映射到相应的事件。

图2自定义的HttpModule

// This module, named HttpModules.CS will be compiled
//? into an assembly named HttpModules.dll
using System;
using System.Web;
namespace HttpModuleExamples {
?? public class CustomHttpModule : IHttpModule {
????? // IHttpModule members
????? public void Init(HttpApplication httpApp) {
???????? httpApp.BeginRequest +=???
?????????? new EventHandler(this.OnBeginRequest);???
???????? httpApp.EndRequest +=
?????????? new EventHandler(this.OnEndRequest);
????? }
????? public void Dispose() {
???????? // Usually, nothing has to happen here...
????? }
????? // event handlers??
????? public void OnBeginRequest(object o, EventArgs ea) {
???????? HttpApplication httpApp = (HttpApplication) o;??
???????? HttpContext ctx = HttpContext.Current;
???????? ctx.Response.Write("Beginning Request
");
????? }
????? public void OnEndRequest(object o, EventArgs ea) {
???????? HttpApplication httpApp = (HttpApplication) o;??
???????? HttpContext ctx = HttpContext.Current;
???????? ctx.Response.Write("Ending Request
");
????? }
?? }
}

2给出了一些C#代码,这些代码定义了一个附加到一个应用程序的BeginRequestEndRequest事件的HttpModule,它为每个请求提供简单的预处理(请求处理之前)和善后处理(请求处理之后)。这些代码被编译到一个程序集并部署到bin文件夹。要想把这个处理程序安装到应用程序处理的一系列环节当中,我们只需象下面的一样在web.config文件当中的httpModule部分声明一下。

下面的代码展示的是一个在处理环节中使用了HttpModule的普通的ASPX文件:

ASP.NET现在开始通过CustomHttpModule的请求开始的OnBeginRequest方法和请求结束时的OnEndRequest方法来跟踪所有的请求。当你浏览到这个页面时你会看到像图3中的一个简单的ASPX页面。

Figure 3 A Simple ASPX Page

图3?一个简单的ASPX页面

HttpModule中你并不是仅仅可以截获BeginRequestEndRequest事件。图4给出了你可以跟踪的并且可以放到HttpModule处理的HttpApplication事件。捕获这些事件只不过需要为你想处理的事件建立一个事件处理程序。图5给出了在HttpModule中截获AuthenticateRequest事件的C#代码。

图4

Event
Occurs
AcquireRequestState
When ASP.NET acquires the current state (for example, session state) associated with the current request
AuthenticateRequest
When a security module has established the identity of the user
AuthorizeRequest
When a security module has verified user authorization
BeginRequest
When the first event in the HTTP pipeline chain of execution responds to a request
Disposed
When ASP.NET completes the chain of execution when responding to a request
EndRequest
When the last event in the HTTP pipeline chain of execution responds to a request
Error
When an unhandled exception is thrown
PostRequestHandlerExecute
When the ASP.NET handler (page, XML Web Service) finishes execution
PreRequestHandlerExecute
Just before ASP.NET begins executing a handler such as a page or XML Web Service
PreSendRequestContent
Just before ASP.NET sends content to the client
PreSendRequestHeaders
Just before ASP.NET sends HTTP headers to the client
ReleaseRequestState
After ASP.NET finishes executing all request handlers; also causes state modules to save the current state data
ResolveRequestCache
When ASP.NET completes an authorization event to let the caching modules serve requests from the cache, bypassing execution of the handler (the page or XML Web Service, for example)
UpdateRequestCache
When ASP.NET finishes executing a handler in order to let caching modules store responses that will be used to serve subsequent requests from the cache

?

图5 截获AuthenticateRequest事件

using System;
using System.Web;
namespace HttpModuleExamples { 
   public class CustomAuthentication : IHttpModule { 
      // IHttpModule members
      public void Init(HttpApplication httpApp) {
         httpApp.BeginRequest +=    
           new EventHandler(this.OnAuthenticateRequest);   
      }
      public void Dispose() {
         // Usually, nothing has to happen here...
      }
      // event handlers   
      public void OnAuthenticateRequest(object o, EventArgs ea) {
         // Do any custom authentication here—perhaps manage 
         //  custom credentials. 
      }
   }
}

提前结束请求

截获HTTP请求最经常的原因是当出现错误时提前结束请求。例如:如果您自己来处理认证,当结果是错误,没有通过认证时,你需要停止此请求。如果你编写了一个SOAP服务器,当一个非SOAP请求到达时你可能需要终端这个请求。HttpApplication类中有一个叫做CompleteRequest的方法,它用来完成请求。你可以调用CompleteRequest并且设置context(上下文)对象的StatusCodeStatusDescription属性,来通知客户端。图6给出了截获一个请求并且当请求是不安全的时就结束它。

图6?提前结束一个Http请求

public class TestSecureConnection : IHttpModule
{
  // IHttpMoule members
  public string ModuleName { ... }
  public void Init(HttpApplication httpApp)
  {
    httpApp.BeginRequest +=
        new EventHandler(this.OnBeginRequest);
  }
  public void Dispose() { ... }
  public void OnBeginRequest(object o, EventArgs ea)
  {
    HttpApplication httpApp = (HttpApplication) o;
    HttpContext ctx = (HttpContext) ea.ExtendedInfo;
    if(!ctx.Request.IsSecureConnection) 
    {
      httpApp.CompleteRequest();
      ctx.Response.StatusCode = 403;
      ctx.Response.StatusDescription =
                   "Use SSL, please.";
    }
  }
}
7 系统提供的HttpModules 

Class
Description
DefaultAuthenticationModule
Insures the presence of an Authentication object in the context
FileAuthorizationModule
Verifies that the remote user has permissions in Windows NT to access the file requested
FormsAuthenticationModule
Turns on ASP.NET forms authentication
PassportAuthenticationModule
Provides a wrapper around Passport authentication services
SessionStateModule
Provides session state services for an application
UrlAuthorizationModule
Provides URL-based authorization services for allowing or denying access to specified resources
WindowsAuthenticationModule
Turns on Windows/IIS authentication for the application

系统提供的模块

很多ASP.NET的性质是通过使用HttpModule技术来增加的,比如说:包括输出缓存、会话状态、Windows验证、窗体验证、Passport验证、URL验证和文件验证。图7给出了这些性质以及实现这些性质的模块。

每个预定义的HttpModule都是在machine.config文件中。图8给出了这些设置。

图?8 预定义的HttpModules注册


  
  
 
   
   
 
   
   
 
   
   
 
   
   
 
   
   
 
   
   
 
   
   

  
  

附到一个应用程序上的一系列的HttpModule表示成对IhttpModule引用的集合,叫做HttpModuleCollection,这些集合可以作为HttpApplication类的Modules属性来访问。在运行时,集合里面包括所有的machine.config中的系统提供的模块和web.config中定义的模块。HttpModuleCollection是一系列对IhttpModule的引用,这些模块或者以它们的名字作为关键字或者ordinal作为关键字,正如图9表示的。图10给出了Web页面当中列出来的模块。

当应用程序启动时,一般来说所有的HttpModule都由ASP.NET控制。如果你想亲自管理这些模块,你可以使用HttpModuleCollection来获得一个对任意模块的引用并调用Init或者Dispose方法。或者你可以手工的装载一个HttpModule程序集而且为你的应用程序增加基于特定的自定义的规则的模块。

图9 判断使用的是哪个模块

public void ShowModules(Object o, EventArgs E) {
? HttpApplication httpApp =
?? HttpContext.Current.ApplicationInstance;
? HttpModuleCollection httpModuleColl =
?? httpApp.Modules;
? Response.Write("
");
? String[] rgstrModuleNames;
? rgstrModuleNames = httpModuleColl.AllKeys;
? foreach(String strModuleName in rgstrModuleNames) {
??? Response.Write(strModuleName);
??? Response.Write("
");
? }
? Response.Write("
");
}
<%@ Page Language="C#"
??? src="UseHttpModules.cs"
??? Inherits="UseHttpModulesPage"
??? trace='true'%>


??

??
??? OnClick=ShowModules runat=server />
??

?

图10附加的HttpModules


Figure 10 Attached HttpModules

?

HttpModules and Global.ASAX

ASP.NET应用程序可能包含一个名为GLOBAL.ASAX的文件(也叫做ASP.NET应用程序文件)。GLOBAL.ASAX位于你的ASP.NET应用程序的根目录下面。当应用程序在运行时被加载,ASP.NET提取GLOBAL.ASAX文件并产生一个从HttpApplication派生的运行时对象。GLOBAL.ASAX是可选的,但是当它存在的话,它包含由ASP.NETHTTP模块产生的与应用程序级别的对应的代码。

?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值