• ASP.NET管道处理模型


    原理说明

    1. Http请求到达服务器,如果是首次Http请求,则会初始化站点(加载路由规则、注册区域、添加过滤器等);
    2. http.sys监听到Http请求,交给aspnet_ISAPI(实现了ISAPI接口的程序),aspnet_ISAPI的isapiRuntime将请求打包成IsapiWorkRequest对象,以下简称wr并将wr对象并放入指定的某个队列,队列与IIS应用程序池对应,http.sys通知w3svc处理队列里的http请求;
    3. .net开始接管请求了,由HttpRunTime接管,从队列取出wr对象,将wr封装成HttpContext(httpContext = new HttpContext(wr, false) 来自HttpRunTime源码,如果HttpContext实例化异常,会wr.EndOfRequest()返回400错误Bad Request,开始进入ASP.NET管道
    4. HttpApplicationFactory这个工厂将HttpContext作为参数,从对象池里创建或获取HttpApplication对象(管道里重要对象之一IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(httpContext);来自HttpRunTime源码,这个对象实现了IHttpHandler接口(一般处理程序就是实现了这个接口),可以自定义这个HttpApplicationFactory._customApplication;,如果没有自定义的,则返回内置的HttpApplication对象之前,如果是首次请求前会初始化,比如执行Global.asax里的Application_Start()方法;
    5. HttpApplication对象初始化时根据配置文件初始化多个HttpModule(管道里重要对象之一),也可以自定义HttpModule为HttpApplication注册事件,HttpApplication有25个事件,依次执行22个事件;
    6. 执行到PostResolveRequestCache事件时,会匹配MVC路由,如果是请求已存在的物理文件,则直接返回;如果匹配到MVC路由则进入MVCHttpHandler,MVCHttpHandler则会通过控制器工厂得到控制器实例、再反射执行MVC的3种Filter、再执行Action,如果未能匹配到路由,则按配置到指定HttpHandler,则进入指定的HttpHandler,如果还是匹配不到HttpHandler,则返回404;
    7. 也可以自定义HttpHandle,用于处理特殊类型的Http请求;
    8. ASP.NET Framework处理一个Http Request的流程:
      HttpRequest–>http.sys–>w3wp.exe–>ASPNET_ISAPI.dll–>AppDomainFactory–>IsapiRuntime–>IsapiWorkerRequest–>HttpRuntime–>HttpContext–>HttpApplicationFactory–>HttpApplication–>HttpModule–>HttpHandlerFactory–>HttpHandler–>HttpHandler.ProcessRequest()–>HttpModule–>http.sys
    9. ASP.NET 请求处理过程是基于管道模型的,这个管道模型是由多个HttpModule(HTTP模块)和最多一个HttpHandler组成,ASP.NET把http请求依次传递给管道中各个HttpModule,最终被HttpHandler处理,处理完成后,再次经过管道中的HttpModule,把结果返回给客户端。我们可以在每个HttpModule中都可以干预请求的处理过程。
    10. 在http请求的处理过程中,只能调用一个HttpHandler,但可以调用多个HttpModule。
    11. HttpHandler处理完请求后,修改队列里对象的状态,IIS将修改状态了的对象通过Socket返回给客户端;
    12. 这个是从网上抄的:这里以IIS6.0为例,它在工作进程w3wp.exe中会利用aspnet_isapi.dll加载.NET运行时。IIS6.0引入了应用程序池的概念,一个工作进程对应着一个应用程序池。一个应用程序池可以承载一个或多个Web应用。如果HTTP.SYS(HTTP监听器,是Windows TCP/IP网络子程序的一部分,用于持续监听HTTP请求)接收的请求是对该Web应用的第一次访问,在成功加载运行时后,IIS会通过AppDomainFactory为该Web应用创建一个应用程序域。也就是说一个应用程序池中会有多个应用程序域,它们共享一个工作进程资源,但是又不会互相牵连影响。随后一个特殊的运行时IsapiRuntime被加载,会接管该HTTP请求。IsapiRuntime首先会创建一个IsapiWorkerRequest对象来封装当前的HTTP请求,随后将此对象传递给ASP.NET运行时HttpRunTime。从此时起,HTTP请求正式进入了ASP.NET管道。HttpRunTime会根据IsapiWorkerRequest对象创建用于表示当前HTTP请求的上下文对象HttpContext。随着HttpContext对象的创建,HttpRunTime会利用HttpApplicationFactory创建或获取现有的HttpApplication对象。HttpApplication负责处理当前的HTTP请求。在HttpApplication初始化过程中,ASP.NET会根据配置文件加载并初始化注册的HttpModule对象。对于HttpApplication来说,在它处理HTTP请求的不同阶段会触发不同的事件,而HttpModule的意义在于通过注册HttpApplication的相应事件,将所需的操作注入整个HTTP请求的处理流程。最终完成对HTTP请求的处理在HttpHandler中,不同的资源类型对应着不同类型的HttpHandler。
    13. http.sys:HTTP协议栈,HTTP Protocol Stack, HTTP监听器,是Windows TCP/IP网络子程序的一部分,用于持续监听HTTP请求

    HttpApplication

    在这里插入图片描述

    1. HttpApplication是整个ASP.NET基础架构的核心,它负责处理分发给它的HTTP请求。
    2. HttpApplication对象里有公开25个事件,以便注入方法,还有HttpContext属性;
    3. global.asax文件为每个Web应用程序提供了一个从HttpApplication派生的Global类。该类包含事件处理程序,如Application_Start。
    4. 每个Web应用程序都会有一个Global实例,作为应用程序的唯一入口,应用程序中只有一个Global对象实例,但是可不是只有一个HttpApplication对象实例。
    5. ASP.NET运行时维护一个HttpApplication对象池;
    6. 按照实现的先后顺序列出了HttpApplication在处理每一个请求时触发的事件名称:
    名称描述
    BeginRequestHTTP管道开始处理请求时,会触发BeginRequest事件
    AuthenticateRequest,PostAuthenticateRequestASP.NET先后触发这两个事件,使安全模块对请求进行身份验证
    AuthorizeRequest,PostAuthorizeRequestASP.NET先后触发这两个事件,使安全模块对请求进程授权
    ResolveRequestCache,PostResolveRequestCacheASP.NET先后触发这两个事件,以使缓存模块直接对请求直接进行响应(缓存模块可以将响应内容进程缓存,对于后续的请求,直接将缓存的内容返回,从而提高响应能力)。
    PostMapRequestHandler对于访问不同的资源类型,ASP.NET具有不同的HttpHandler对其进程处理。对于每个请求,ASP.NET会通过扩展名选择匹配相应的HttpHandler类型,成功匹配后,该实现被触发
    AcquireRequestState,PostAcquireRequestStateASP.NET先后触发这两个事件,使状态管理模块获取基于当前请求相应的状态,比如SessionState
    PreRequestHandlerExecute,PostRequestHandlerExecuteASP.NET最终通过一请求资源类型相对应的HttpHandler实现对请求的处理,在实行HttpHandler前后,这两个实现被先后触发
    ReleaseRequestState,PostReleaseRequestStateASP.NET先后触发这两个事件,使状态管理模块释放基于当前请求相应的状态
    UpdateRequestCache,PostUpdateRequestCacheASP.NET先后触发这两个事件,以使缓存模块将HttpHandler处理请求得到的相应保存到输出缓存中
    LogRequest,PostLogRequestASP.NET先后触发这两个事件为当前请求进程日志记录
    EndRequest整个请求处理完成后,EndRequest事件被触发
    1. 对于一个ASP.NET应用来说,HttpApplication派生于global.asax文件,我们可以通过创建global.asax文件对HttpApplication的请求处理行为进行定制。global.asax采用一种很直接的方式实现了这样的功能,这种方式既不是我们常用的方法重写(Method Overriding)或者事件注册,而是直接采用方法名匹配。在global.asax中,我们按照这样的方法命名规则进行事件注册:Application_{Event Name}。比如Application_BeginRequest方法用于处理HttpApplication的BeginRequest事件。
    2. HttpApplication扩展有2种办法(对http请求处理,新增功能):
      1. 自定义HttpModule,下面会说到;
      2. 在Global里新增方法,方法命名规则:HttpModule名称_事件名称,其中事件名称的事件可以在HttpModule里新增,或沿用asp.net默认加载的HttpModule,比如Seesion_start(),一般用于ASP.NET默认HttpModule进行扩展;

    HttpModule

    1. 在HttpApplication初始化过程中,ASP.NET会根据配置文件(ASP.NET默认配置+项目自己的web.config)加载并初始化注册的HttpModule对象,注册的HttpModule对象初始化后,存放在了HttpApplication的Modules属性之中
    2. ASP.NET默认配置其路径位于:C:WindowsMicrosoft.NETFramework64v4.0.30319Configweb.config的httpModules节点里,当然也可以删除系统默认的HttpModule,即在项目的web.config文件HttpModules节点里,新增
    3. HttpModule是针对所有请求的,且Modules集合中的所有HttpModule都要依次执行请求处理;
    4. 自定义一个HttpModule,首先新增一个比如名称为MyHttpModule的类并实现IhttpModule接口的类,以便对ASP.NET管道进行处理,比如:session鉴权、黑白名称、日志、URL改写等;
    5. 实现接口的方法说明:
      1. Dispose方法:这个方法给予HTTP模块在对象被垃圾收集之前执行清理的机会。此方法一般无需编写代码。
      2. Init()方法:HttpApplication对象一共25个管道事件,给需要的事件注册方法;
        1. BeginRequest 当ASP.NET运行时接收到新的HTTP请求的时候引发这个事件。
        2. AuthenticateRequest 当ASP.NET 运行时准备验证用户身份的时候引发这个事件。
        3. AuthorizeRequest 当ASP.NET运行时准备授权用户访问资源的时候引发这个事件。
    6. IIS7集成模式中,配置文件web.config里system.webServer节点下modules新增一行 ,完成以上2步自定义HttpModule完成;
    7. HttpModule生命周期示意图:
      HttpModule生命周期示意图
      事件的触发顺序:
      事件的触发顺序

    HttpHandler

    1. 与HttpModule针对所有的请求文件不同,HttpHandler是针对某一类型的文件(比如图片防盗链,jpg、gif等后缀的配置为指定的HttpHandler里判断referer,或者Word文档类配置为指定HttpHandler处理,不给下载),如果http上下文(httpContext)是请求存在的物理文件:IsRouteToExistingFile(httpContext),则不会走MVC的路由,否则可能要设置MVC的忽略路由;
    2. HttpHandler是HTTP请求的处理中心,真正地对客户端请求的服务器页面做出编译和执行,并将处理过后的信息附加在HTTP请求信息流中再次返回到HttpModule中,HttpHandler与HttpModule不同,一旦定义了自己的HttpHandler类,那么它对系统的HttpHandler的关系将是“覆盖”关系,但也有可能被HttpModule拦截掉,请求到不了HttpHandler;
    3. 和HttpModule一样,HttpHandler对象的建立与请求路径模式之间的映射关系,也需要通过配置文件,如果这种类型的请求,匹配到了MVC的路由,则要新增一个忽略路由设置,忽略MVC路由,用web.config里的path匹配;
    4. 在C:WindowsMicrosoft.NETFramework64v4.0.30319Configwebconfig文件中,也可以找到ASP.NET内置的HttpHandler配置。
    5. 自定义一个HttpHandle,新增一个类,名称以Handle结尾,比如ZZHandler.cs,实现IHttpHandler接口,一般处理程序.ashx,就是实现了IHttpHandler接口的类;
    6. 实现接口方法/属性的说明:
      1. IsReusable:返回false;
      2. ProcessRequest():处理逻辑,最终调用context.Response.Write(),返回内容;
    7. 修改配置文件web.config:
      Web.Config配置文件
          <httpHandlers>
           <add name="ZZ" verb="*" path="*" type="类全名,DLL文件名"></add>
          </httpHandlers>
          <!--
    		Verb属性:指定了处理程序支持的HTTP动作。*-支持所有的HTTP动作;“GET”-支持Get操作;“POST”-支持Post操作;“GET, POST”-支持两种操作。
    		Path属性:指定了需要调用处理程序的路径和文件名(可以包含通配符)。“*”、“*.aspx”、“showImage.aspx”、“test1.aspx,test2.aspx”,如果匹配到MVC的路由,则要新增一个忽略路由设置
    		Type属性:类全名,DLL文件名-->
    

    MVC管道区别

    • MVC与一般处理程序、ASPX等的管道基本是一致的,只是MVC管道新增了一个UrlRoutingModule(HttpModule),并在Init方法里,为HttpApplication对象的PostResolveRequestCache事件注册了动作,注意,是在MapRequestHeadler事件前,MapRequestHeadler事件是读取web.config里的Handlers节点的文件后缀,以便匹配Handler;
      • 用http上下文(httpContext)匹配MVC路由,得到路由匹配结果,如果请求的是已存在的文件,则返回null,所以请求已存在的文件,不会匹配MVC的路由规则,UrlRoutingModule扩展无效;
        在这里插入图片描述
      • 然后用路由结果(不为空,匹配到了路由)获取一个IRouteHandler对象;
      • IRouteHandler对象,获取一个HttpHandler,即一个MvcHandler,所以MVC也最终由MvcHandler处理的;
        在这里插入图片描述
    • MvcHandler源码里的ProcessRequest()方法,会生成对应控制器对象,控制器对象再调用方法controller.Execute(this.RequestContext),再调用ExecuteCore得到Action名称,最后执行Filter(权限验证、AcitonFilter等)以及方法本身;在这里插入图片描述

    返回结果

    • ActionResult是抽象类,里面有个抽象方法:ExecuteResult(),比如JsonResult类,就是设置一下ContentType="application/json"以及将数据序列化写入Response里去,所以也可以自定义一个ActionResult,比如XMLResult实现处理结果用XML返回,只要重写ExecuteResult方法即可;
    • 在控制器实例化后,调用的是:ControllerActionInvoker–InvokeAction—查询Filter并执行–OnActionExecuting–Action执行–OnActionExecuted—OnResultExecuting–ActionResult.ExecuteResult生成返回结果到Respose—OnResultExecuted
    • 如果不是返回View(),则直接将数据写入Respose里去;
    • 如果返回的是View(),则其中ExecuteResult方法执行大致步骤:FindView–Render–把cshtml生成的类.Execute()方法生成html拼接好并写入response,cshtml其实是System.Web.Mvc.WebViewPage派生的子类;
  • 相关阅读:
    常用数据绑定控件详解
    BookList
    BUG:TreeView: NodeCheck Event Does Not Occur
    SQL Server中TEXT类型操作
    Quote:软件开发工程师的经验之谈
    SQL字符串处理函数大全
    Summary 2009 Target 2010
    读取库中的所有表名 列名
    使用大值数据类型
    sql 修改列名及表名 sp_rename
  • 原文地址:https://www.cnblogs.com/zoulei0718/p/14315573.html
Copyright © 2020-2023  润新知