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:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config中的web.config,然后找到system.web节点下面的HttpModules下Module,一般系统自带的webconfig不要轻易去修改,因为这个是针对于全局的。如果要修改只需要修改自己项目中的webconfig
B:打开项目所在的webconfig,注释见下图:
4:怎么自定义module
右键 -》添加新项 --》选择Asp.net模块即自己定义的一个module已经创建完成。
module的注册一般都是在Init方法里面来完成的,整个过程分为以下几步:
- 当站点第一个资源被访问的时候,Asp.Net会创建HttpApplication类的实例,它代表着站点应用程序,同时会创建所有在Web.Config中注册过的Module实例。
- 在创建Module实例的时候会调用Module的Init()方法。
- 在Init()方法内,对想要作出响应的HttpApplication暴露出的事件进行注册。(仅仅进行方法的简单注册,实际的方法需要另写)。
- HttpApplication在其应用程序周期中触发各类事件。
- 触发事件的时候调用Module在其Init()方法中注册过的方法。
- Dispose():它可以在进行垃圾回收之前进行一些清理工作
下面附上自己新定义的module代码:
public class CustomHttpModule : IHttpModule
{
public void Dispose()
{
Console.WriteLine();
} public event EventHandler CustomHttpModuleHandler; /// <summary>
/// 注册动作
/// </summary>
/// <param name="context"></param>
public void Init(HttpApplication application)
{
#region 为每一个事件,都注册了一个动作,向客户端输出信息
application.AcquireRequestState += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "AcquireRequestState "));
application.AuthenticateRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "AuthenticateRequest "));
application.AuthorizeRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "AuthorizeRequest "));
application.BeginRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "BeginRequest "));
application.Disposed += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "Disposed "));
application.EndRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "EndRequest "));
application.Error += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "Error "));
application.LogRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "LogRequest "));
application.MapRequestHandler += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "MapRequestHandler "));
application.PostAcquireRequestState += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostAcquireRequestState "));
application.PostAuthenticateRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostAuthenticateRequest "));
application.PostAuthorizeRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostAuthorizeRequest "));
application.PostLogRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostLogRequest "));
application.PostMapRequestHandler += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostMapRequestHandler "));
application.PostReleaseRequestState += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostReleaseRequestState "));
application.PostRequestHandlerExecute += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostRequestHandlerExecute "));
application.PostResolveRequestCache += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostResolveRequestCache "));
application.PostUpdateRequestCache += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PostUpdateRequestCache "));
application.PreRequestHandlerExecute += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PreRequestHandlerExecute "));
application.PreSendRequestContent += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PreSendRequestContent "));
application.PreSendRequestHeaders += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "PreSendRequestHeaders "));
application.ReleaseRequestState += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "ReleaseRequestState "));
application.RequestCompleted += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "RequestCompleted "));
application.ResolveRequestCache += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "ResolveRequestCache "));
application.UpdateRequestCache += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>来自MyCustomModule 的处理,{0}请求到达 {1}</h1><hr>", DateTime.Now.ToString(), "UpdateRequestCache "));
#endregion
}
}
自己定义的module已经完成,这样创建完成后,module还不会生效,如果想要其生效,需要在webconfig中的<system.webServer>(因为是该节点是针对于IIS中的集成模式)节点中配置:
<add name="CustomHttpModule" type="Ruanmou.MVC5.Utility.Pipeline.CustomHttpModule,Ruanmou.MVC5"/>
这样既可生效。具体详细配置见上面的第3点
另外还可以这样去新建module,然后注册方法如上配置webconfig,同样浏览的时候页面上面会看到module输出的信息:
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() {
}
}
注意:module是针对于应用级,而不是页面级别的,即是只要注册module,则程序中所有的页面都会生效的!
5:怎么看当前请求中运用到了哪些module以及事件呢,可以通过下面代码来查看:
public ActionResult Module()
{
HttpApplication app = base.HttpContext.ApplicationInstance; #region 得到当前请求中所有的Event事件
List<SysEvent> sysEventsList = new List<SysEvent>();
int i = ;
foreach (EventInfo e in app.GetType().GetEvents())
{
sysEventsList.Add(new SysEvent()
{
Id = i++,
Name = e.Name,
TypeName = e.GetType().Name
});
}
#endregion #region 得到当前HttpApplication中所有的module,包括系统自带跟自己自定义的
List<string> list = new List<string>();
foreach (string item in app.Modules.Keys)
{
list.Add($"{item}: {app.Modules.Get(item)}");
}
#endregion ViewBag.Modules = string.Join(",", list);
return View(sysEventsList);
}
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:然后具体代码如下:
public class CustomHandler : IHttpHandler
{
//MSDN上是这样解释的:获取一个值,该值指示其他请求是否可以使用 IHttpHandler 实例。也就是说后继的Http请求是不是可以继续使用实现了该接口的类的实例,一般来说,我把它设置成true。
public bool IsReusable => true; public void ProcessRequest(HttpContext context)
{
//Console.WriteLine("This is AAAA");
context.Response.Write("This is AAAA");
context.Response.ContentType = "text/html";
}
}
3.3:然后在 <system.webServer>节点下的 <handlers>增加如下:
<handlers>
<add name="rtmp" verb="*" path="*.rtmp" type="Ruanmou.MVC5.Utility.Pipeline.CustomHandler,Ruanmou.MVC5"/>
</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。
Asp.net管道模型之(HttpModules 和 HttpHandler)的更多相关文章
- Asp.net管道模型(管线模型)
Asp.net管道模型(管线模型) 前言 为什么我会起这样的一个标题,其实我原本只想了解asp.net的管道模型而已,但在查看资料的时候遇到不明白的地方又横向地查阅了其他相关的资料,而收获比当初预 ...
- Asp.net管道模型(管线模型)之一发不可收拾
前言 为什么我会起这样的一个标题,其实我原本只想了解asp.net的管道模型而已,但在查看资料的时候遇到不明白的地方又横向地查阅了其他相关的资料,而收获比当初预想的大了很多. 有本篇作基础,下面两篇就 ...
- 关于asp.net mvc中的httpModules 与 httpHandler
ASP.NET对请求处理的过程: 当请求一个*.aspx文件的时候,这个请求会被inetinfo.exe进程截获,它判断文件的后缀(aspx)之后,将这个请求转交给ASPNET_ISAPI.dll,A ...
- ASP.NET-HTTP管道模型
HTTP管道模型处理WEB程序很小的一方面.管道模型是类似于Web Services的一种在服务器端处理ASP.NET页面的框架技术 一.管道对象模型 在System.Web的命名空间中处理HTTP的 ...
- ASP.Net 管道模型 VS Asp.Net Core 管道 总结
1 管道模型 1 Asp.Net Web Form管道 请求进入Asp.Net工作进程后,由进程创建HttpWorkRequest对象,封装此次请求有关的所有信息,然后进入HttpRuntime类进 ...
- ASP.NET管道模型简析
我相信在第一次听到这个名词时,有的小伙伴会一脸懵,而且还有很多疑问,其实我在第一次接触这个概念时跟很多小伙伴一样一脸懵. 接下来我将以我自己的理解来讲述什么是管道模型. 什么是管道模型 首先有没有小伙 ...
- asp.net管道模型
查了很多资料,终于大概弄懂管道模型(注意并非指定是asp.net范畴)是个什么概念了,其实就是从Unix移植过来的一种概念,也可以说是一种模式吧(只允许一头读,一头写,并且读完了就会自动消失). as ...
- Owin管道与asp.net管道模型
------2016.3.6 更新 文中提到没有Microsoft.Owin.Host.SystemWeb 这个dll 便不会加载Startup.Configuration,因为这个dll 其中有个O ...
- asp.net 管道模型+生命处理周期
http://www.cnblogs.com/qianlifeng/archive/2010/12/16/1908568.html https://msdn.microsoft.com/zh-cn/l ...
随机推荐
- VM虚拟机Android安装图形界面
摘自,转 https://blog.csdn.net/weixin_42633191/article/details/89391188
- Tomcat 学习总结(1) --Servlet技术
在Web应用中,Servlet是一门重要的技术,Servlet是利用Java类编写的服务端程序,与平台架构,协议无关. JSP的实质就是Servlet,因为所有的JSP页面传回服务端时要转为Servl ...
- Html学习之一(锚点链接的使用,页面间的跳转)
页面一: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <ti ...
- 用java写爬虫
今天学了怎么用java代码获取要爬取页面的源代码,因为只写了一点,所以接下来会陆续跟新此文章 首先,看一下我写的代码 这就是爬取下来的网页源代码,第一张图刚刚补注释有个注释写错了,别误导你们就行,接下 ...
- IPv6地址编址
- (三十七)golang--如何获取命令行参数
1.第一种方式 缺点:参数的接收受输入的顺序所影响. 2.第二种方式(使用flag包)
- 【shell脚本】定时备份数据库===dbbackup.sh
定时备份数据库是很有必要的 一.脚本内容 [root@localhost dbbackup]# cat dbbackup.sh #!/bin/bash #备份数据库 mysqldump -uroot ...
- redis命令之 ----List(列表)
BLPOP BRPOP BRPOPLPUSH LINDEX LINDEX key index 返回列表 key 中,下标为 index 的元素. 下标(index)参数 start 和 stop 都以 ...
- F#周报2019年第18期
新闻 FableConf 2019开始征集提案 2019理事会选举 如同DSL一般的Elmish封装器fable-elmish,可以创建控制台或者终端界面 介绍VS Code的远程开发 F#(.NET ...
- 【Maven】【IDEA】在idea中开发web项目,解决maven的jar包冲突的方法
在idea中开发web项目,解决maven的jar包冲突的方法 第一步: 先对项目进行 clean ,再进行install 第二步: 出现NoSuchMethodException,ClassNotF ...