ASP.NET页面与IIS底层交互和工作原理详解(第三回)

8/10/2015来源:ASP.NET技巧人气:2432

asp.net页面与IIS底层交互和工作原理详解(第三回)

引言

Http 请求处理流程和Http Handler 介绍这两篇文章里,我们首先了解了Http请求在服务器端的处理流程,随后我们知道Http请求最终会由实现了IHttpHandler接口的类进行处理(应该记得Page类实现了IHttpHandler)。从Http 请求处理流程一文的最后的一幅图中可以看到,在Http请求由IHttpHandler处理之前,它需要通过一系列的Http Module;在请求处理之后,它需要再次通过一系列的Http Module,那么这些Http Module是如何组成的?用来做什么呢?本文将对Http Module作以介绍。

Http Module概述

暂时先不考虑我们自己实现Http Module的情况。在.Net中,Http Module 是实现了IHttpModule接口的程序集。IHttpModule 接口本身并没有什么好大写特写的,由它的名字可以看出,它不过是一个普普通通的接口而已。实际上,我们关心的是实现了这些接口的类,如果我们也编写代码实现了这个接口,那么有什么用途。一般来说,我们可以将Asp.Net中的事件分成三个级别,最顶层是 应用程序级事件、其次是页面级事件、最下面是控件级事件,事件的触发分别与 应用程序周期、页面周期、控件周期紧密相关。 Http Module 的作用是与应用程序事件密切相关的。

我们通过Http Module在Http请求管道(Pipeline)中注册期望对应用程序事件做出反应的方法,在相应的事件触发的时候(比如说BeginRequest事件,它在应用程序收到一个Http请求并即将对其进行处理时触发),便会调用Http Module注册了的方法,实际的工作在这些方法中执行。.Net 本身已经有很多的Http Module,其中包括 表单验证Module(FormsAuthenticationModule), session 状态Module(SessionStateModule),输出缓存Module (OutputCacheModule)等。

注册 Http Module

在注册我们自己编写的 Http Module 之前,先来看看Asp.Net中已经有的HttpModule。与 Http Handler类似,我们需要打开机器上C:\WINDOWS\Microsoft.NET\Framework\ v2.0.50727\CONFIG 目录下的 web.config 文件。找到 <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" />... 略</httpModules>

我们先从结点上看,type属性与上一节所说的http handler结点的type属性类似,都代表了相应的程序集。但是,与http handler 不同,module只提供了一个name属性,没有诸如 path这样指定某一特定(或者用通配符 * 代表某一种类)文件的处理程序。这是与Module的特点相关的,我们知道 module 是响应应用程序周期中触发的事件,对于所有提交到aspnet_isapi.dll的请求都一样,即便请求只是像类似http://www.tracefact.net/images/logo.gif 这样获取一张图片而已(对ISAPI进行过设置以后,默认aspnet_isapi.dll不接手图片文件)。

与Http handler类似,在这册我们自己的http module 时,假设类名为ModuleDemo,位于myNameSpace命名空间下,程序集名称为myDll,我们只需将myDll.dll拷贝到Bin目录下,并在站点的 web.config 文件 system.web 结点下创建 httpModules 结点:

<system.web> <httpModules> <add name="CustomModuleName" type="myNameSpace.ModuleDemo, myDll"/> </httpModules></system.web>

type属性由分号“,”分为两部分,前面是命名空间及类名,也就是类型名;后面是程序集名。如果我们将代码创建在App_Code目录中,则不需要再指定程序集名。

name属性由我们自己命名,不一定与类名相同,此处我将它命名为“CustomModuleName”。我们可以通过应用程序(Httpapplication)的Modules属性获取HttpModuleCollection集合,然后通过name属性,进一步获取HttpModule对象。

通过name属性,我们还可以在global.asax中文件中编写自定义HttpModule暴露出的事件的处理程序,它采用的格式是:void ModuleName_EventName(object sender, EventArgs e)。我们将在后面做更详细介绍。

Asp.Net 内置的 Http Modules

下面这张表格列出了C:\WINDOWS\Microsoft.NET\Framework\ v2.0.50727\CONFIG下的Web.Config中的 Asp.Net 内置的Http Modules 及其主要作用。

名称

类型

功能

OutputCache

System.Web.Caching.OutputCacheModule

页面级输出缓存

Session

System.Web.SessionState.SessionStateModule

Session状态管理

WindowsAuthentication

System.Web.Security.WindowsAuthenticationModule

用集成Windows身份验证进行客户端验证

FormsAuthentication

System.Web.Security.FormsAuthenticationModule

用基于Cookie的窗体身份验证进行客户端身份验证

PassportAuthentication

System.Web.Security.PassportAuthenticationModule

用MS护照进行客户身份验证

RoleManager

System.Web.Security.RoleManagerModule

管理当前用户角色

UrlAuthorization

System.Web.Security.UrlAuthorizationModule

判断用户是否被授权访问某一URL

FileAuthorization

System.Web.Security.FileAuthorizationModule

判断用户是否被授权访问某一资源

AnonymousIdentification

System.Web.Security.AnonymousIdentificationModule

管理Asp.Net应用程序中的匿名访问

PRofile

System.Web.Profile.ProfileModule

管理用户档案文件的创立 及相关事件

ErrorHandlerModule

System.Web.Mobile.ErrorHandlerModule

捕捉异常,格式化错误提示字符,传递给客户端程序

我们将在后面用编程的方式来查看它。

IHttpModule接口

看了这么多理论知识,本节将开始动手写点程序,实现自己的Http Module。我们首先需要看下IHttpModule 接口,它包括下面两个方法:

public void Init(HttpApplication context);public void Dispose();

Init():这个方法接受一个HttpApplication对象,HttpApplication代表了当前的应用程序,我们需要在这个方法内注册 HttpApplication对象暴露给客户端的事件。可见,这个方法仅仅是用来对事件进行注册,而实际的事件处理程序,需要我们另外写方法。

整个过程很好理解:

  • 当站点第一个资源被访问的时候,Asp.Net会创建HttpApplication类的实例,它代表着站点应用程序,同时会创建所有在Web.Config中注册过的Module实例。
  • 在创建Module实例的时候会调用Module的Init()方法。
  • 在Init()方法内,对想要作出响应的HttpApplication暴露出的事件进行注册。(仅仅进行方法的简单注册,实际的方法需要另写)。
  • HttpApplication在其应用程序周期中触发各类事件。
  • 触发事件的时候调用Module在其Init()方法中注册过的方法。

NOTE:如果你不了解事件注册等相关内容,请参阅C#中的委托与事件一文。

Dispose():它可以在进行垃圾回收之前进行一些清理工作。

综上所述:实现一个 IHttpModule 的模板一般是这样的:

public class ModuleDemo:IHttpModule{ public void Init(HttpApplication context) { // 注册HttpApplication应用程序 BeginRequest 事件 // 也可以是其他任何HttpApplication暴露出的事件 context.BeginRequest += new EventHandler(context_BeginRequest); } void context_BeginRequest(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; HttpContext context = application.Context; // 做些实际的工作,HttpContext对象都获得了,剩下的基本可以自由发挥了 } public void Dispose() { }}

通过Http ModuleHttp请求输出流中写入文字

本例中,我们仅用BeginRequest事件和 EndRequest 事件对 Http Module 的使用作以说明。我们通过这个范例,了解 Http Module 基本的使用方法。

首先,请创建一个新的站点,在App_Code目录中添加类文件: ModuleDemo.cs:

public class ModuleDemo:IHttpModule{ // Init方法仅用于给期望的事件注册方法 public void Init(HttpApplication context) { context.BeginRequest += new EventHandler(context_BeginRequest); context.EndRequest += new EventHandler(context_EndRequest); } // 处理BeginRequest 事件的实际代码 void context_BeginRequest(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; HttpContext context = application.Context; context.Response.Write("<h1 style='color:#00f'>来自HttpModule 的处理,请求到达</h1><hr>"); } // 处理EndRequest 事件的实际代码 void context_EndRequest(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; HttpContext context = application.Context; context.Response.Write("<hr><h1 style='color:#f00'>来自HttpModule的处理,请求结束</h1>"); } public void Dispose() { }}

上面的代码很简单,它注册了 HttpApplication实例的 BeginRequest 事件