zoukankan      html  css  js  c++  java
  • 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

    欢迎分享学习!!!

  • 相关阅读:
    基于live555的视频直播 DM368IPNC RTSP分析
    C语言中的二级指针(双指针)
    SQL中的IF ELSE(CASE语句的使用)
    Ubuntu下Postgres安装与配置
    虚拟机+ubuntu 图形界面和终端界面的切换
    中科院 2014年工程硕士入学专业课笔试考场安排
    中科院 2014年GCT考前辅导课程安排
    中科院 工程硕士专业课 复试考试前的辅导安排
    中国科学院大学工程管理与信息技术学院 2014年招收以下八个领域在职工程硕
    中国科学院大 工程管理与信息技术学院 在职工程硕士资格审查和复试重要通知
  • 原文地址:https://www.cnblogs.com/wangjinya/p/13733234.html
Copyright © 2011-2022 走看看