Asp.net管道模型之(HttpModules 和 HttpHandler)

上一节我们从大概范围介绍了管道模型的整体流程,我们从其中知道管道最重要的两大组件为:HttpModules 跟 HttpHandler。今天我们着重来介绍一下这两大组件

一:asp.net处理管道

从请求进入ASP.NET工作者进程,直至它到达最终的处理程序之前要经过一系列的步骤和过程,这个步骤和过程称为ASP.NET处理管道。

管道模型使用一个HttpContext对象去描述声明request/response信息。这个对象在HttpApplication和handler之间来回传递。HttpContext对象通过属性来描述request和response信息。下图展示了部分HttpContext类常用的属性。            

二:Module的详解

1:HttpModule:可以看做是一个拦截器,给我们在特定的事件处理请求的机会。HttpModule有很多应用,例如,我们要在每个请求的页面事件前加载Session数据,那么就用到SessionModule等等;

2:asp.net4.0提供了路由机制也是建立在一个UrlRouteModule上面的,它在请求映射到具体程序前拦截,然后重新映射。MVC又是建立在路由机制的基础上的。

3:怎么查看系统默认自带的Module以及怎么配置自定义的module。

    A:打开C:WindowsMicrosoft.NETFramework64v4.0.30319Config中的web.config,然后找到system.web节点下面的HttpModules下Module,一般系统自带的webconfig不要轻易去修改,因为这个是针对于全局的。如果要修改只需要修改自己项目中的webconfig

     B:打开项目所在的webconfig,注释见下图:

4:怎么自定义module

右键 -》添加新项 --》选择Asp.net模块即自己定义的一个module已经创建完成。

module的注册一般都是在Init方法里面来完成的,整个过程分为以下几步:

  1. 当站点第一个资源被访问的时候,Asp.Net会创建HttpApplication类的实例,它代表着站点应用程序,同时会创建所有在Web.Config中注册过的Module实例。
  2. 在创建Module实例的时候会调用Module的Init()方法。
  3. 在Init()方法内,对想要作出响应的HttpApplication暴露出的事件进行注册。(仅仅进行方法的简单注册,实际的方法需要另写)。
  4. HttpApplication在其应用程序周期中触发各类事件。
  5. 触发事件的时候调用Module在其Init()方法中注册过的方法。
  6. Dispose():它可以在进行垃圾回收之前进行一些清理工作

下面附上自己新定义的module代码:

 1 public class CustomHttpModule : IHttpModule
 2     {
 3         public void Dispose()
 4         {
 5             Console.WriteLine();
 6         }
 7 
 8         public event EventHandler CustomHttpModuleHandler;
 9 
10         /// <summary>
11         /// 注册动作
12         /// </summary>
13         /// <param name="context"></param>
14         public void Init(HttpApplication application)
15         {
16             #region 为每一个事件,都注册了一个动作,向客户端输出信息
17             application.AcquireRequestState += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "AcquireRequestState        "));
18             application.AuthenticateRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "AuthenticateRequest        "));
19             application.AuthorizeRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "AuthorizeRequest           "));
20             application.BeginRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "BeginRequest               "));
21             application.Disposed += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "Disposed                   "));
22             application.EndRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "EndRequest                 "));
23             application.Error += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "Error                      "));
24             application.LogRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "LogRequest                 "));
25             application.MapRequestHandler += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "MapRequestHandler          "));
26             application.PostAcquireRequestState += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostAcquireRequestState    "));
27             application.PostAuthenticateRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostAuthenticateRequest    "));
28             application.PostAuthorizeRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostAuthorizeRequest       "));
29             application.PostLogRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostLogRequest             "));
30             application.PostMapRequestHandler += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostMapRequestHandler      "));
31             application.PostReleaseRequestState += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostReleaseRequestState    "));
32             application.PostRequestHandlerExecute += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostRequestHandlerExecute  "));
33             application.PostResolveRequestCache += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostResolveRequestCache    "));
34             application.PostUpdateRequestCache += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostUpdateRequestCache     "));
35             application.PreRequestHandlerExecute += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PreRequestHandlerExecute   "));
36             application.PreSendRequestContent += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PreSendRequestContent      "));
37             application.PreSendRequestHeaders += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PreSendRequestHeaders      "));
38             application.ReleaseRequestState += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "ReleaseRequestState        "));
39             application.RequestCompleted += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "RequestCompleted           "));
40             application.ResolveRequestCache += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "ResolveRequestCache        "));
41             application.UpdateRequestCache += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "UpdateRequestCache         "));
42             #endregion
43         }
44     }
View Code

自己定义的module已经完成,这样创建完成后,module还不会生效,如果想要其生效,需要在webconfig中的<system.webServer>(因为是该节点是针对于IIS中的集成模式)节点中配置:

 <add name="CustomHttpModule" type="Ruanmou.MVC5.Utility.Pipeline.CustomHttpModule,Ruanmou.MVC5"/>

 这样既可生效。具体详细配置见上面的第3点

另外还可以这样去新建module,然后注册方法如上配置webconfig,同样浏览的时候页面上面会看到module输出的信息:

 1 public class ModuleDemo:IHttpModule
 2 {
 3     // Init方法仅用于给期望的事件注册方法
 4     public void Init(HttpApplication context) {
 5        context.BeginRequest += new EventHandler(context_BeginRequest);
 6        context.EndRequest += new EventHandler(context_EndRequest);
 7     }
 8 
 9     // 处理BeginRequest 事件的实际代码
10     void context_BeginRequest(object sender, EventArgs e) {
11        HttpApplication application = (HttpApplication)sender;
12        HttpContext context = application.Context;
13        context.Response.Write("<h1 style='color:#00f'>来自HttpModule 的处理,请求到达</h1><hr>");
14     }
15 
16     // 处理EndRequest 事件的实际代码
17     void context_EndRequest(object sender, EventArgs e) {
18        HttpApplication application = (HttpApplication)sender;
19        HttpContext context = application.Context;
20        context.Response.Write("<hr><h1 style='color:#f00'>来自HttpModule的处理,请求结束</h1>"); 
21     }
22        
23     public void Dispose() {
24     }
25 }
View Code

注意:module是针对于应用级,而不是页面级别的,即是只要注册module,则程序中所有的页面都会生效的!

5:怎么看当前请求中运用到了哪些module以及事件呢,可以通过下面代码来查看:

 1  public ActionResult Module()
 2  {
 3      HttpApplication app = base.HttpContext.ApplicationInstance;
 4 
 5      #region 得到当前请求中所有的Event事件
 6      List<SysEvent> sysEventsList = new List<SysEvent>();
 7      int i = 1;
 8      foreach (EventInfo e in app.GetType().GetEvents())
 9      {
10          sysEventsList.Add(new SysEvent()
11          {
12              Id = i++,
13              Name = e.Name,
14              TypeName = e.GetType().Name
15          });
16      }
17      #endregion
18 
19      #region 得到当前HttpApplication中所有的module,包括系统自带跟自己自定义的
20      List<string> list = new List<string>();
21      foreach (string item in app.Modules.Keys)
22      {
23          list.Add($"{item}: {app.Modules.Get(item)}");
24      }
25      #endregion
26 
27      ViewBag.Modules = string.Join(",", list);
28      return View(sysEventsList);
29  }
View Code

6:每个module的功能用途

名称

类型

功能

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

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

三:管道中19个标准事件(每发一次都基本上会走下面的流程)

1:HttpHandler:可以看做一个处理器,它负责处理请求,输出数据。aspx,ashx或者说实现了IHttpHandler的都是HttpHandler。

2:系统的web.config配置的默认的对应的处理器。是根据后缀名然后映射到不同的处理器上面

随便找一个.aspx对应的handler,通过反编译会得到证实

3:自定义Handler处理器

3.1:右键新建项然后选择下图

3.2:然后具体代码如下:

 1  public class CustomHandler : IHttpHandler
 2     {
 3         //MSDN上是这样解释的:获取一个值,该值指示其他请求是否可以使用 IHttpHandler 实例。也就是说后继的Http请求是不是可以继续使用实现了该接口的类的实例,一般来说,我把它设置成true。
 4         public bool IsReusable => true; 
 5 
 6         public void ProcessRequest(HttpContext context)
 7         {
 8             //Console.WriteLine("This is AAAA");
 9             context.Response.Write("This is AAAA");
10             context.Response.ContentType = "text/html";
11         }
12     }
View Code

3.3:然后在 <system.webServer>节点下的 <handlers>增加如下:

1     <handlers>
2       <add name="rtmp" verb="*" path="*.rtmp" type="Ruanmou.MVC5.Utility.Pipeline.CustomHandler,Ruanmou.MVC5"/>
3     </handlers>

如果想要映射多个后缀可以:

<httpHandlers>
<add path="*.wss,*.rss" type=" 命名空间.类名,命名空间" verb="GET,POST," />
</httpHandlers>

注意:这里,path指的是请求的文件名称,可以使用通配符扩大范围,也可以明确指定这个handler仅用于处理某个特定的文件(比如说:filename.aspx)的请求。verb指的是请求此文件的方式,可以是post或get,用*代表所有访问方式。type属性由“,”分隔成两部分,第一部分是实现了接口的命名空间.类名,第二部分是位于Bin目录下的编译过的程序集名称。 

3.4:最后在App_Start下面的RouteConfig里面配置一下路由过滤器,不然会一直走路由匹配:

 routes.IgnoreRoute("CustomService/{*pathInfo}");//以CustomService开头,都不走路由

3.5:这样即可,可以在浏览器输入:

 

我们可以使用介个方式来做一个图片防盗链的功能。

4:系统自带默认的事件

   注意:我们每次请求都会走下面的事件,然后会根据我们请求的后缀名然后去找对应的处理Handler,然后进行处理请求响应。

 

四:总结

  MVC URLRouting Module对进入server的request进行了拦截,然后对request的handlerjinxingltes的处理。asp.net WebForm和asp.net MVC两者的不同,是在于最终使用的IHttpHandle的不同。WebForm中使用的是Page这个Handler,MVC中使用的是MVCHander。 

原文地址:https://www.cnblogs.com/loverwangshan/p/11195554.html