asp.net本质论——HttpModule

处理 HttpApplication 的事件
 
HttpApplication 提供了基于事件的扩展机制,允许程序员借助于处理管道中的事件进行处理过程扩展。由于 HttpApplication 对象是由 ASP.NET 基础架构来创建和维护的,那么,如何才能获取这个对象引用,以便于注册 HttpApplication 对象的事件处理,就是程序员首先要解决的问题。在 ASP.NET 中,提供了两种方式来解决这个问题:IHttpModule 方式和 global.asax 方式。这两种方式的核心都是 IHttpModule 接口。
 
通过 IHttpModule 创建 HttpApplication 的事件处理程序
 
在 ASP.NET中,定义在System.Web 命名空间下的 IHttpModule 接口专门用来定义 HttpApplication对象的事件处理。
 
实现 IHttpModule 接口的类称为 HttpModule。IHttpModule 接口的定义如下,其中仅仅包含两个成员:
 
public interface IHttpModule  {
      void Dispose()
      void Init( HttpApplication context )
  }
 
其中,Dispose 方法用于回收 Module 所使用的非托管资源,如果没有的话,直接返回即可。
 
最重要的是 Init 方法,可以看到,这个方法接收一个 HttpApplication 类型的参数,在 ASP.NET 中,每当创建一个 HttpApplication 对象实例,将遍历注册的 HttpModule 类型,通过反射,依次创建每个注册 HttpModule 类型的一个实例对象,并将这个 HttpApplication 实例通过 Init 方法传递给各个 HttpModule,这样 HttpModule 就可以在第一时间完成针对 HttpApplication 对象的事件注册了。
 
例如,希望写一个处理 PostAuthenticateRequest 事件的 HttpModule,那么,可以如下完成事件的注册:
 
public void Init(System.Web.HttpApplication application)  
{
      application.PostAuthenticateRequest 
       += new EventHandler(Application_PostAuthenticateRequest);  
}
 
注册 HttpModule
 
在 ASP.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 中,类的全名为 com.aspnet.OnlineUserModule,将这个自定义的 HttpModule 注册到网站中,那么配置文件中的定义如下所示:
 
<httpModules>
    <add name="online" type="com.aspnet.OnlineUserModule,OnlineUserModule"/>
</httpModules>
 
对于 IIS 7.0来说,需要在配置文件的 system.webServer 配置节中注册 HttpModule。注意此时的配置元素名称变为了 modules。 在 IIS 7.0 中,可以为 MapRequestHandler,LogRequest 和 PostLogRequest 事件添加处理程序。只有在 IIS 7.0 集成模式下运行并且与 .NET Framework 3.0 或更高版本一起运行的应用程序,才可以支持这些事件。
 
<system.webServer>
   <modules>
     <add name="ModuleExample" type="Samples.ModuleExample"/>
   </modules>
</system.webServer>
 
托管代码模块也可以在 IIS 7.0 配置存储区(ApplicationHost.config 文件)的 modules 元素中注册。在 ApplicationHost.config 文件中注册的模块具有全局范围,因为它们为所有由 IIS 7.0 承载的 Web 应用程序而注册。同样,在 ApplicationHost.config 文件的 globalModules 元素中定义的本机代码模块也具有全局范围。如果 Web 应用程序不需要全局模块,则可以将其禁用。
 
不使用配置文件注册 HttpModule
 
在 ASP.NET 4.0 中,还可以不通过修改配置文件来完成 Moudle 的注册。从 .NET 3.5 开始,新提供的 PreApplicationStartMethodAttribute 特征可以应用在程序集上,使得自定义的网站初始化代码可以在 Web 应用程序的Application_Start初始化环节之前就执行。这个步骤甚至在动态编译和执行 Application_Start 之前。对于每个程序集,可以定义一次。特征的定义如下:
 
[AttributeUsageAttribute(AttributeTargets.Assembly,AllowMultiple = false)]
public sealed class PreApplicationStartMethodAttribute : Attribute  {
      public Type Type { get; }
      public string MethodName { get; }
      ......  
}
 
Type 用来指定定义了初始化方法的类型,MethodName 用来指定将要执行的初始化方法。
 
这样,可以不在配置文件中固定配置 HttpModule,而是定义一个方法,这个方法可以返回需要动态注册的 HttoModule,将这个方法以委托的形式登记在一个集合中。在网站启动之后,每当 HttpApplicationFactory 创建一个 HttpApplication 对象,完成正常注册的 HttpModule 创建及初始化之后,再来创建我们动态注册的这些 HttpModule。
 
对于 HttpApplication 来说,其 Init 方法将在网站正常注册的 HttpModule 创建及注册之后被调用,用来完成自定义的 HttpApplication 初始化。我们可以在这个时间点动态注册 HttpModule。在 ASP.NET 网站中,Global.asax 文件用来生成一个 HttpApplication 的派生类,这个类用来创建网站中使用的 HttpApplication 对象,我们可以重写这个派生类的 Init 方法,完成动态注册的 HttpModule 创建和注册工作。
 
<script runat="server">
      private List<IHttpModule> dynamicModules;
      public override void Init()
      {
          base.Init();
           this.dynamicModules = DynamicHttpModuleManager.GetModules();
          foreach (IHttpModule module in this.dynamicModules)
          {
              module.Init(this);
          }
      }
//这个在Global.asax文件
 
在网站初始化之前,将需要注册的 Module 类型记录在一个集合中。
 
public delegate IHttpModule CreateDynamicHttpModule(  );

public static class DynamicHttpModuleManager
{
      private 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 。
 
namespace DiskFileUpload
{
      public class UploadModule : System.Web.IHttpModule
      {
          public static void Register()
          {
              DynamicHttpModuleManager.RegisterDynamicModule
                  (
                      ()=>new UploadModule()
                  );
          }
      }
}
 
最后,在项目的 AssemblyInfo.cs 文件中增加 PreApplicationStartMethod 特征完成动态注册。
 
[assembly: PreApplicationStartMethod(typeof(DiskFileUpload.UploadModule),"Register")]
 
常见的 HttpModule
 
在 ASP.NET 中,已经预定义了许多HttpModule,甚至已经在服务器的网站配置文件中进行了注册,在系统文件夹 C:\Windows\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>
 
主要的HttpModule的解释如下:
 
OutputCacheMudole 完成ASP.NET的输出缓存管理工作。
 
OutputCacheMudole的配置参数通过system.web配置元素的caching子元素的 outputCache元素进行定义。当启用输出缓存之后,OutputCacheMudole 将注册 HttpApplication 的ResolveRequestCache 和 UpdateRequestCache 两个事件完成输出缓存的管理。
 
SessionStateModule 完成 Session 的管理工作。
 
这个 Module 的配置参数通过配置文件中的 system.web 配置元素的 sessionState 子元素进行配置。当启用 Session 状态管理之后,SessionStateModule 将注册 HttpApplication 的AcquireRequestState、ReleaseRequestState、EndRequest三个事件完成 Session 状态的管理工作。
 
ProfileModule 在 .NET 2.0 之后,提供个性化数据管理。
 
这是一个自定义的类似于 Session 的会话状态管理,但是,个性化数据的读取和保存可以由程序员完全控制,并且提供了强类型的数据访问方式。这个 Module 的配置参数在 system.web 的子元素 profile 中进行说明。当启用了个性化数据管理之后,Module 将注册 HttpApplicaiton 的 AcquireRequestState 和EndRequest 事件处理。
 
AnonymousIdentificationModule 提供匿名用户的标识。
 
是否启用匿名用户标识在配置文件的system.web配置元素的子元素 anonymousIdentification 中定义,还可以配置匿名标识的管理方式。由于在 AuthenticateRequest 事件中将验证用户,获取用户名,所以,这个 Module 注册了 PostAuthenticateRequest 的事件处理,当用户没有经过验证的时候,为用户分配一个唯一的匿名标识。
 
WindowsAuthenticationModule、FormsAuthenticationModule和PassportAuthenticationModule用来完成用户的验证工作。
 
它们通过配置文件中 system.web 的子元素 authentication 子元素定义,mode 属性用来指定网站当前使用的验证方式,也就是哪一个 Module 将被用来完成验证工作。在启用验证的情况下,FormsAuthenticationModule 和 PassportAuthenticationModule将注册 HttpApplication 的AuthenticateRequest 和 EndRequest 事件进行用户的验证处理。 WindowsAuthenticationModule 将注册 AuthenticateRequest 的事件处理。
 
RoleManagerModule、UrlAuthorizationModule、FileAuthorizationModule 用来完成用户的授权管理。
 
授权管理的配置参数来自 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; }
 
可以使用定义 HttpModule 时候的 name 做为索引器来获取对应的 HttpModule。例如,获取前面定义的 HttpModule 对象的引用,可以如下进行。
 
application. Modules["online" ]
 
然后,就可以定义这个 HttpModule 的事件处理了。
 
不过,这样比较麻烦,更加简单的方式是在 Global.asax 中进行事件处理。
 




posted @ 2012-12-22 03:35  Adming  阅读(500)  评论(0编辑  收藏  举报