原文:
HttpApplication对象是ASP.NET中处理请求的重要对象,但是,这种类型的对象实例不是由程序员来创建的,而是由ASP.NET帮助我们创建的。为了便于扩展处理工作,HttpApplication采用处理管道的方法进行处理,将处理的过程分为多个步骤,每个步骤通过事件的形式暴露给程序域,这些事件按照固定的处理顺序依次触发,程序员通过编写事件处理方法就可以自定义每一个请求的扩展处理过程。
对于HttpApplication来说,到ASP.NET 4.0版本,提供了19个标准事件,如下表:可参见MSDN:http://msdn.microsoft.com/zh-cn/library/system.web.httpapplication.aspx 序号 | 名称 | 说明 |
1 | ASP.NET开始处理的第一个时间,表示处理的开始 | |
2 | 验证请求,一般用来取得请求的用户信息 | |
3 | 已经获取请求的用户信息 | |
4 | 授权,一般用来检查用户的请求是否获得权限 | |
5 | 用户请求已经得到授权 | |
6 | 获取以前处理缓存的处理结果,如果以前缓存过,那么不必再进行请求的处理工作,直接返回缓存结果 | |
7 | 已经完成缓存的存取工作(在 事件之后和 事件之前,会创建一个事件处理程序(一个对应于请求 URL 的页)。 如果服务器在集成模式下运行 IIS 7.0 并且 .NET Framework 至少为 3.0 版本,则会引发 事件。 如果服务器在经典模式下运行 IIS 7.0 或者运行的是较早版本的 IIS,则无法处理此事件。) | |
8 | 已经根据用户的请求,创建了处理请求的处理器对象 | |
9 | 取得请求的状态,一般用于Session | |
10 | 已经取得了Session | |
11 | 准备执行处理程序(执行事件处理程序。) | |
12 | 已经执行了处理程序 | |
13 | 释放请求的状态 | |
14 | 已经释放了请求的状态(在引发 事件之后,现有的所有响应筛选器都将对输出进行筛选。) | |
15 | 更新缓存 | |
16 | 已经更新了缓存 | |
17 | . | 请求的日志操作(仅在 IIS 7.0 处于集成模式并且 .NET Framework 至少为 3.0 版本的情况下才支持此事件。) |
18 | 已经完成了请求的日志操作(仅在 IIS 7.0 处于集成模式并且 .NET Framework 至少为 3.0 版本的情况下才支持此事件。) | |
19 | 本次请求处理完成 |
- public interface IHttpModule
- {
public interface IHttpModule {
void Dispose() vodi Init(HttpApplication context)
- void Dispose()
- vodi Init(HttpApplication context)
- }
}
创建和注册自定义 HTTP 模块 MSDN:http://msdn.microsoft.com/zh-cn/library/ms227673.aspx 其中,Dispose方法用于回收Module所使用的非托管资源,如果没有的话,直接返回即可。 最重要的是Init方法,可以看到,这个方法接受一个HttpApplication类型的参数,在ASP.NET中,每当创建一个HttpApplication对象实例,将遍历注册的HttpModule类型,通过反射,依次创建每个注册HttpModule类型的实例对象,并将这个HttpApplication实例通过Init方法传递给各个HttpModule,这样HttpModule就可以在第一时间完成针对HttpApplication对象的事件注册了。 例如,希望写一个处理PostAuthentiacteRequest事件的HttpModule,那么,可以如下完成事件的注册:- public void Init(HttpApplication context)
- {
- context.PostAuthorizeRequest += new EventHandler(context_PostAuthorizeRequest);
- }
public void Init(HttpApplication context) { context.PostAuthorizeRequest += new EventHandler(context_PostAuthorizeRequest); }
注册 HttpModule 在APS.NET中,实现IHttpModule接口只是实现HttpModule的第一步,在ASP.NET中所使用的HttpModule还必须在网站配置文件中进行注册才能真正生效,并在ASP.NET中使用。 在.NET中,网站的配置文件分为三个级别,首先在.NET的系统文件夹中,有针对本服务器所有.NET程序的配置文件,配置文件所在的文件夹位于如下位置: 操作系统文件夹\Microsoft.NET\Framework\ASP.NET版本\Config 在这个文件夹中,有两个重要的配置文件:machine.config 和 web.config。machine.config配置文件中保存有针对此服务器所有.NET程序的基本配置参数。web.config配置文件中保存有针对此服务器所有Web应用程序的基本配置参数。在我们开发的网站项目中的web.config中所做的配置是专门针对这个网站应用程序的配置文件,在网站应用程序中起作用的配置参数来自这三个配置文件的整合。 在ASP.NET的网站配置文件web.config中,system.web配置元素的子元素httpModules用来配置网站所使用的HttpModule;httpModules的子元素add用来增加一个新的HttpModule;clear将清除前面注册的所有HttpModule。 add元素有两个必选的属性name 和type,简介如下: name表示这个HttpModule在程序中的名字,在网站应用程序中,可以通过这个名字来找到HttpModule对象的引用。HttpApplication的Modules属性表示这个对象所管理的所有HttpModule对象,通过这个name作为索引器,可以找到对应的HttpModule对象。 type表示HttpModule对象的类型名,ASP.NET网站可以使用这个类型名,通过反射来动态创建HttpModule对象。类型哦写法就是反射中要求的类型名称写法,如果这个类型定义在网站中,那么,就是一个博阿含命名空间哦类的全名,否则的话,在全名的后面,使用逗号(,)分隔,还需要跟上类型所在程序集的名称,这个程序集的名称不需要包含.dll扩展名。例如,自定义的HttpModule类位于程序集OnlineUserModule中,类的全名为Samples.AspNet.CS.CustomHTTPModule,将这个自定义的HttpModule注册到网站中,那么配置文件中的定义如下所示:
以下设置适用于 IIS 7.0 经典模式以及较早的 IIS 版本。- <configuration>
- <system.web>
- <httpModules>
- <add type="Samples.AspNet.CS.CustomHTTPModule,OnlineUserModule"
- name="CustomHttpModule" />
- </httpModules>
- </system.web>
- </configuration>
<configuration> <system.web> <httpModules> <add type="Samples.AspNet.CS.CustomHTTPModule,OnlineUserModule" name="CustomHttpModule" /> </httpModules> </system.web> </configuration>
以下设置适用于 IIS 7.0 集成模式。
- <configuration>
- <system.webServer>
- <modules>
- <add type="Samples.AspNet.CS.CustomHTTPModule,OnlineUserModule"
- name="CustomHttpModule" />
- </modules>
- </system.webServer>
- </configuration>
<configuration> <system.webServer> <modules> <add type="Samples.AspNet.CS.CustomHTTPModule,OnlineUserModule" name="CustomHttpModule" /> </modules> </system.webServer> </configuration>
对于IIS 7.0,可以为MapRequestHandler,LogRequest和PostLogRequest事件添加处理程序。只有在IIS 7.0集成模式下运行并且与 .NET Frameword 3.0或更高版本一起运行的应用程序,才可以支持这些事件。
托管代码模块也可以在IIS 7.0配置存储区(ApplicationHost.config文件)的modules元素中注册。在ApplicationHost.config文件中注册的模块具有全局范围,因为它们为所有由IIS 7.0承载的应用程序而注册。同样,在ApplicationHost.config文件的globalModules元素中定义的本机代码模块也具有全局范围。如果Web应用程序不需要全局模块,则可以将其禁用。不使用配置文件注册HttpModule 在APS.NET 4.0 中,还可以不通过修改配置文件来完成Module的注册。从。NET3.5开始,新提供的PreApplicationStartMethodAttribute特征可以应用在程序集上,使得自定义的网站初始化代码可以在Web应用程序的Application_Start初始化环节之前就执行。这个步骤设置在动态编译和执行Application_Start之前。对于每个程序集,可以定义依次。特征的定义如下。- [AttributeUsageAttribute(AttributeTargets.Assembly, AllowMultiple = false)]
- public sealed class PreApplicationStartMethodAttribute : Attribute
- {
- public Type Type{ get;}
- public string MethorName{ get;}
- ......
- }
[AttributeUsageAttribute(AttributeTargets.Assembly, AllowMultiple = false)] public sealed class PreApplicationStartMethodAttribute : Attribute { public Type Type{get;} public string MethorName{get;} ...... }
Type用来指定定义了初始化方法的类型,MethodName用来指定将要执行的初始化的方法。 这样,可以不再配置文件中固定配置HttpModule,而是定义一个方法,这个方法可以返回需要动态注册的HttpModule,将这个方法以委托的形式登记在一个集合中。在网站启动之后,每当HttpApplicationFactory创建一个HttpAppplication对象,完成正常注册的HttpModule创建及初始化之后,再来创建我们动态注册的这些HttpModule。 对于HttpApplication来说,其Init方法将在网站正常注册的HttpModule创建及注册之后被调用,用来完成自定义的HttpApplication初始化。我们可以在这个时间点动态注册HttpModule。在ASP.NET网站中,Global.asax文件用来生成一个HttpApplication的派生类,这个类用来创建网站中使用的HttpApplication对象,我们可以重写这个派生类的Init方法,完成动态注册的HttpModule创建和注册工作。Global.asax- private List<IHttpModule> dynamicModules;
- public override void Init()
- {
- base.Init();
- this.dynamicModules
- = DynamicHttpModuleManager.GetModules();
- foreach (IHttpModule module in this.dynamicModules)
- {
- module.Init(this);
- }
- }
private List<IHttpModule> dynamicModules; public override void Init() { base.Init(); this.dynamicModules = DynamicHttpModuleManager.GetModules(); foreach (IHttpModule module in this.dynamicModules) { module.Init(this); } }在网站初始化之前,将需要注册的Module类型记录在 一个集合中。
- public delegate IHttpModule CreateDynamicHttpModule();
- public static class DynamicHttpModuleManager
- {
- public static List<CreateDynamicHttpModule> _createModuleHandlerList =
- new List<CreateDynamicHttpModule>();
- public static void RegisterDynamicModule(
- CreateDynamicHttpModule handler)
- {
- _createModuleHandlerList.Add(handler);
- }
- public static List<IHttpModule> GetModules()
- {
- List<IHttpModule> list = new List<IHttpModule>();
- foreach (CreateDynamicHttpModule handler in _createModuleHandlerList)
- {
- IHttpModule module = handler();
- list.Add(module);
- }
- return list;
- }
- }
public delegate IHttpModule CreateDynamicHttpModule(); public static class DynamicHttpModuleManager { public static List<CreateDynamicHttpModule> _createModuleHandlerList = new List<CreateDynamicHttpModule>(); public static void RegisterDynamicModule( CreateDynamicHttpModule handler) { _createModuleHandlerList.Add(handler); } public static List<IHttpModule> GetModules() { List<IHttpModule> list = new List<IHttpModule>(); foreach (CreateDynamicHttpModule handler in _createModuleHandlerList) { IHttpModule module = handler(); list.Add(module); } return list; } }
在Module中增加一个用户注册的方法Register,注意,必须是public 和static- public class Class1:IHttpModule
- {
- public static void Register()
- {
- DynamicHttpModuleManager.RegisterDynamicModule
- (
- ()=>new Class1()
- );
- }
public class Class1:IHttpModule { public static void Register() { DynamicHttpModuleManager.RegisterDynamicModule ( ()=>new Class1() ); }
最后,在项目的AssemblyInfo.cs文件中增加PreApplicationStartMethod特征完成动态注册。- [assembly: PreApplicationStartMethod(typeof(WebApplication1.Class1),"Register")]
[assembly: PreApplicationStartMethod(typeof(WebApplication1.Class1),"Register")]
在ASP.NEt中,已经与定义了许多HttpModule,甚至已经在服务器的网站配置文件中进行了注册,在系统文件夹 系统目录\Microsoft.NET\Framework\v4.0.30319\Config中,web.config文件中已经注册了14个HttpModule。- <httpModules>
- <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" />
- <add name="Session" type="System.Web.SessionState.SessionStateModule" />
- <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" />
- <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
- <add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule" />
- <add name="RoleManager" type="System.Web.Security.RoleManagerModule" />
- <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />
- <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" />
- <add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule" />
- <add name="Profile" type="System.Web.Profile.ProfileModule" />
- <add name="ErrorHandlerModule" type="System.Web.Mobile.ErrorHandlerModule, System.Web.Mobile, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
- <add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
- <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />
- <add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
- </httpModules>
<httpModules> <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" /> <add name="Session" type="System.Web.SessionState.SessionStateModule" /> <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" /> <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" /> <add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule" /> <add name="RoleManager" type="System.Web.Security.RoleManagerModule" /> <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" /> <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" /> <add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule" /> <add name="Profile" type="System.Web.Profile.ProfileModule" /> <add name="ErrorHandlerModule" type="System.Web.Mobile.ErrorHandlerModule, System.Web.Mobile, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" /> <add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </httpModules>
主要的HttpModule的解释如下:OutputCacheModule完成ASP.NET的输出缓存管理工作。 OutputCacheModule的配置参数通过system.web配置元素的caching子元素的outputCache元素进行定义。当启用输出缓存之后,OutputCacheModule将注 册 HttpApplication的ResolverRequestcache和UpdateRequestcache两个事件完成输出缓存管理。SesionStateModule完成Sesion管理工作。 这个Module的配置参数通过配置文件中的system.web配置元素的sessionState子元素进行配置。当启用Session状态管理之后,SessionStateModule将注册HttpApplication的AcquireRequestState、ReleaseRequestState、EndRequest三个事件完成Session状态的管理工作。ProfileModule在.NET2.0之后,提供个性化数据管理。 这是一个自定义的类似于Session的回环状态管理,但是,个性化数据的读取和保存可以由程序员完全控制,并且提供了强类型的数据访问方式。这个Module的配置参数在system.web的子元素profile中进行说明。当启用了个性化数据管理之后,Module将注册HttpApplication的AcquireRequestState和EndRequest事件处理。AnonymousIdentifiactionModule提供匿名用户标识。 是否启用匿名用户标识在配置文件的system.web配置元素的子元素anonymodusIdentification中定义,还可以配置匿名标识的管理方式。由于在AuthenticateRequest事件中将验证用户,获取用户名,所以,这个Module注册了PostAuthenticateRequest的事件处理,当用户没有经过验证的时候,为用户分配一个唯一的匿名标识。WindowsAuthenticationModule、FormsAuthentiactionModule和PassportAuthenticationModule用来完成用户验证工作。 它们通过配置文件中的system.web的子元素authentication子元素定义,mode属性用来指定网站当前使用的验证方式,也就是哪一个Module将被用来完成验证工作。在启用验证的情况下,FormsAuthenticationModule和PassprotauthenticationModule将注册HttpApplication的AuthenticateRequest和EndRqeust事件进行用户的验证处理。WindowsAuthenticaitonModule将注册AuthenticateRequest的事件处理。RoleManagerModule、UrlAuthorizationModule、FileAuthorizetionModue用来完成用户的授权管理。 授权管理的配置参数来自system.web的authorization子元素。UrlAuthorizationModule和FileAuthorizationModule注册了HttpApplication的AuthorizeRequest事件处理,用来检查Url和文件的访问授权。RoleManagerModule在Url和文件访问授权检查通过之后,通过用户的标识和角色来完成用户的授权检查,RoleManagerModule注册了HttpApplication的PostAuthenticateRequest和EndRequest事件处理。HttpModule的事件 每个HttpModule也可以触发自定义的事件,但是,处理这些HttpModule事件更加麻烦一些,因为这些HttpModule对象实例也不是我们自己创建的。 一般来说,可以通过HttpApplication的Modules属性获取特定的HttpModule,这个属性的定义如下- public HttpModuleCollection Modules { get; }
public HttpModuleCollection Modules { get; }
可以使用定义HttpModule时候哦name作为索引器来获取对应的HttpModule。例如获取前面定义的HttpModule对象的引用,可以如下进行:
- application,Modules["CustomHttpModule"];
application,Modules["CustomHttpModule"];
然后,就可以定义这个HttpModule的事件处理了。不过这样比较麻烦,更简单的方式是在global.asax中进行事件处理。global.asax中HttpApplication事件的自动注册 在global.asax中,针对HttpApplication的事件处理,可以通过定义特殊命令的方法来实现。首先,这些方法必须符合System.EventHandler,因为所有的HttpApplication管道事件都是用这个委托定义。第二,方法的作用于必须是public。第三,方法的命名格式必须如下:Application_注册的事件名称。按照这种命名方法定义在global.asax中的方法将被自动注册到对应事件中。 例如,希望在global.asax中注册PostAuthentiacteRequest事件处理,按么global.asax中应该定义一个如下的方法:- void Appliaction_PostAuthenticateRequest(object sender, EventArgs e)
- {
- //....
- }
void Appliaction_PostAuthenticateRequest(object sender, EventArgs e) { //.... }