MVC请求管道详细总结梳理。

MVC请求管道

一、请求到达IIS之前是这样的:

 

 

 二、到达IIS之后是这样的:

Sys服务监听到有请求到达IIS,IIS会把这个请求转发给ISAPI,ISAPI即Internet Server Application Program Interface (互联网应用服务接口),是微软提供的一套面向Internet服务的API接口,它根据后缀判断需要把该请求转发给谁处理,.net的请求会转发到asp.net_ISAPI,它属于IIS,运行在IIS进程中的,它会用Pipeline的方式把请求转交给.Net Framework,它很像一个队列(先进先出),可以对请求进行排队处理,在请求处理完,会释放掉该请求占用的socket链接。

三、请求到达应用程序:

HTTPRuntime.ProcessRequest是整个应用程序的入口,这一步会接收上一步打包的HTTPWorkerRequest,完成HttpContext的初始化,调用HttpApplicaFactory工厂类创建HttpApplication(HttpApplication实现了IHttpHandler),HttpApplicationFactory.GetApplicationInstance创建HttpApplication实例中有三个关键方法:
           1. HttpApplicationFactory._theApplicationFactory.EnsureInited()该方法检查HttpApplicationFactory是否被初始化(它是存放在一个栈里面的)如果没有,就通过HttpApplicationFactory.Init()进行初始化。在Init()中,先获取Global.asax文件的完整路径,然后调用CompileApplication()对Global.asax进行编译。
           2. HttpApplicationFactory._theApplicationFactory.EnsureAppStartCalled(context)  创建特定的HttpApplication实例,触发ApplicationOnStart事件,执行ASP.Global.asax中的Application_Start(object sender, EventArgs e)方法。这里创建的HttpApplication实例在处理完事件后,就被回收。
           3. HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(context) 该方法创建HttpApplication实例并进行初始化,调用System.Web.HttpApplication.InitInternal()方法。创建HttpApplication实例是根据实际的_theApplicationType进行创建。如果Web目录中没有global.asa文件,也就是说没有动态编译生成ASP.Global.asax类型,那就直接实例化HttpApplication。如果创建了ASP.Global.asax类型,那就对ASP.Global.asax进行实例化。

 

图2.

 

 

 

 

 四、请求到达mvc

  当请求到达应用程序之后,第一站就是路由模块,MVC会根据RouteTable(一般都在RouteConfig中配置,在MVC第一次启动时,路由系统就会把我们注册的路由规则,写在Glocal.asax中的Application_Start事件中)中配置的路由模板去匹配当前的请求,获取对应的Controller和Action信息,具体的匹配过程是由UrlRoutingModule(System.Web.Routing.UrlRoutingModule)来实现的。

      当UrlRoutingModule在Route Table中找到一条匹配的路由规则时,就会为这条路由规则寻找对应的IRouteHandler(System.Web.Mvc.IRouteHandler)实例(默认是System.Web.MvcRouteHandler),根据这个RouteHandler最后获取一个IHttpHandler的实例(默认是System.Web.MvcHandler)。在处理完路由信息和匹配到之后,就来到了Controller。

      在MvcHandler中的ProcessRequest方法中就是ASP.NET MVC的生命周期,这个方法使用IControllerFactory的实例(默认是System.Web.Mvc.DefaultControllerFactory)来创建相应的Controller。

      创建完Controller之后,就会执行Controller的invokeAction()方法,找到合适的Action后,就是Model Binding(默认是System.Web.Mvc.DefaultModelBinder),它会从Http请求的参数中提取数据并实现类型转换,数据校验(例如是否必填,数据格式等)以及是否自动装配到Action方法的参数中。

       完成模型绑定之后就是执行Filter了,Filter也是一个可以铺开说的知识,这里先只简单的介绍一下,从下图看到第一个是Authentication Filter,它是MVC5中新增的一个Filter,它会先于Authorization Filter执行,目的是对访问用户的认证。在MVC5之前,认证和授权都是通过Authorization Filter来实现的。然后是Authorization Filter 这个主要是验证授权的,授权验证通过后执行的Action Filter,自定义Action Filter需继承ActionFilterAttribute,它分为两个方法,OnActionExecuting和OnActionExecuted分别在action执行前后执行,我们可以通过实现IActionFilter接口来实现你个性化的过滤机制。在Action Filter执行之后,就会执行我们的业务代码了。

       在执行完业务代码,会执行ActionResult,ActionResult也有一个Filter,自定义ActionResult Filter需继承ActionFilterAttribute它也分为两个方法:OnResultExecuting和OnResultExecuted,它是在动作结果被执行之前和之后运行。ActionResult就是把后台处理的用户请求结果返回。因此ViewResult、PartialViewResult、RedirectToRouteResult、RedirectResult、ContentResult、JsonResult、FileResult 和 EmptyResult就是具体的返回类型。

      最后还有一个Exception Filter,它只有在当Action执行发生未处理异常的时候执行OnException方法。自定义Exception Filter需要继承HandleErrorAttribute类,重写OnException方法。

      在ActionResult执行完成之后,就是View的初始化和渲染了,ViewResult最终是由View Engine通过调用IView的Render()方法来呈现View的,整个处理过程是由IViewEngine(System.Web.Mvc.IViewEngine)来实现的。ASP.Net MVC 默认提供WebForm(.aspx)和Razor(.cshtml)模板引擎。

五、请求管道中的相关方法有如下:

(1)BeginRequest: 开始处理请求

(2)AuthenticateRequest授权验证请求,获取用户授权信息

(3):PostAuthenticateRequest获取成功

(4): AuthorizeRequest 授权,一般来检查用户是否获得权限

(5):PostAuthorizeRequest:获得授权

(6):ResolveRequestCache:获取页面缓存结果

 

(7):PostResolveRequestCache 已获取缓存 当前请求映射到MvcHandler(pr): 创建控制器工厂 ,创建控制器,调用action执行,view→response

//action Handler : PR()

(8):PostMapRequestHandler 创建页面对象:创建 最终处理当前http请求的 Handler 实例: 第一从HttpContext中获取当前的PR Handler ,Create

(9):PostAcquireRequestState 获取Session

(10)PostAcquireRequestState 获得Session

(11)PreRequestHandlerExecute:准备执行页面对象
执行页面对象的ProcessRequest方法

(12)PostRequestHandlerExecute 执行完页面对象了

(13)ReleaseRequestState 释放请求状态

(14)PostReleaseRequestState 已释放请求状态

(15)UpdateRequestCache 更新缓存

(16)PostUpdateRequestCache 已更新缓存

(17)LogRequest 日志记录

(18)PostLogRequest 已完成日志

(19)EndRequest 完成、

六、怎么实现请求管道中的方法:下面示例就是实现管道中的第9个事件,判断session是否存在事件。

public class ValidateSessionHttpModule:IHttpModule
    {
        public void Dispose()
        {
            throw new NotImplementedException();
        }

        public void Init(HttpApplication context)
        {
            //第九个事件
           context.AcquireRequestState+=context_AcquireRequestState;
        }
        public void context_AcquireRequestState(object sender, EventArgs e)
        {
            HttpApplication application = sender as HttpApplication;
            HttpContext context=application.Context;//获取当前的HttpContext
           string url= context.Request.Url.ToString();//获取用户请求的URL地址。
           if (url.Contains("Admin"))
           {
               if (context.Session["userInfo"] == null)
               {
                   context.Response.Redirect("/Login.aspx");
               }
           }
        }
    }

上面这个只是第一步,下面是很重要的第二步:配置文件中添加system.webService节点。

  <!--关于HttpModule的配置-->
  <system.webServer>
    <modules>
      <add name="ValidateSessionHttpModule" type="CZBK.ItcastProject.Common.ValidateSessionHttpModule"/>
    </modules>
  </system.webServer>

以上代码是什么意思呢?意思就是说,当加载管道事件的时候,会读取管道中的system.webService所有的配置项,并且便利加载注入在管道中。然后当请求到对应步骤的时候,就会进行应用进去。

 

 

还有一种注册管道中事件的方法,估计大家都没有注意到,哪就是我们的global.aspx文件。

public class Global : System.Web.HttpApplication
    {
        /// <summary>
        /// Web应用程序第一次启动时调用该方法,并且该方法只被调用一次。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Application_Start(object sender, EventArgs e)
        {
           
        }
        /// <summary>
        /// 开始会话。(用户通过浏览器第一次访问我们网站中的某个页面,这时建立会话,但是当该用户通过浏览器再次访问其它的页面时,该方法不会被执行。SessionId)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Session_Start(object sender, EventArgs e)
        {// Application:服务端的状态保持机制。放在该对象中的数据是共享的。 Cache
            Application.Lock();
            int count = Convert.ToInt32(Application["count"]);
            count++;
            Application["count"] = count;
            Application.UnLock();
        }
        protected void Application_BeginRequest(object sender, EventArgs e)
        {

        }

        protected void Application_AuthenticateRequest(object sender, EventArgs e)
        {

        }

        
        /// <summary>
        /// 全局的异常处理点。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Application_Error(object sender, EventArgs e)
        {
            //Exception ex = HttpContext.Current.Server.GetLastError();
            ///ex.Message
            ///写到日志中。
                //Log4Net
        }
        /// <summary>
        /// 会话结束
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Session_End(object sender, EventArgs e)
        {
            Application.Lock();
            int count = Convert.ToInt32(Application["count"]);
            count--;
            Application["count"] = count;
            Application.UnLock();
        }


        protected void Application_End(object sender, EventArgs e)
        {

        }
    }

谢谢学习,以上就是本次总结的基本内容,其中部分内容摘自:https://www.cnblogs.com/bobo-pcb/p/11717289.html

欢迎分享学习!!!

 

posted @ 2020-09-26 00:13  锦大大的博客呀!  阅读(477)  评论(0编辑  收藏  举报