mvc请求管道(一)
一、前言
在平常做后台开发的时候,经常会说到请求管道,很多开发者都知道这个,也能说几句,可能没法详细的去介绍,今天就来详细的说一下这个。
二、到达IIS之前
请看下面这个流程图。从用户打开浏览器到请求到达服务器,这些都是需要我们去配置就行了,这里面有一些知识点,http/https、tcp/ip、dns解析这些感兴趣的可以去了解一下。
三、请求到达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进行实例化。
五、请求到达MVC的处理管线
上面大概介绍了Asp.Net 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)模板引擎,你也可以通过实现IViewEngine接口来实现你自己的ViewEngine,然后在Application_Start方法中做如下操作:
protected void Application_Start() { //移除所有的View引擎包括Webform和Razor ViewEngines.Engines.Clear(); //注册你自己的View引擎 ViewEngines.Engines.Add(new CustomViewEngine()); }
在页面里,我们可以直接写html标签,也可以用@Html等来实现。@Html是使用Html Helpers来生成我们需要的html标签,当然它也支持自定义和扩展,这样就可以解决我们一些定制化的需求。
六、总结
在上面所有的操作都完成之后,IIS会把结果返回给用户,用户才能看到他需要的结果。在整个请求管道中,一般分为19个事件,如下,
事件名称: |
简单描述: |
BeginRequest |
在 ASP.NET 响应请求时作为 HTTP 执行管线链中的第一个事件发生 |
AuthenticateRequest |
当安全模块已建立用户标识时发生。注:AuthenticateRequest 事件发出信号表示配置的身份验证机制已对当前请求进行了身份验证。预订 AuthenticateRequest 事件可确保在处理附加的模块或事件处理程序之前对请求进行身份验证
|
PostAuthenticateRequest |
当安全模块已建立用户标识时发生。PostAuthenticateRequest 事件在 AuthenticateRequest 事件发生之后引发。预订 PostAuthenticateRequest 事件的功能可以访问由 PostAuthenticateRequest 处理的任何数据 |
AuthorizeRequest |
当安全模块已验证用户授权时发生。AuthorizeRequest 事件发出信号表示 ASP.NET 已对当前请求进行了授权。预订 AuthorizeRequest 事件可确保在处理附加的模块或事件处理程序之前对请求进行身份验证和授权 |
PostAuthorizeRequest |
在当前请求的用户已获授权时发生。PostAuthorizeRequest 事件发出信号表示 ASP.NET 已对当前请求进行了授权。预订PostAuthorizeRequest 事件可确保在处理附加的模块或处理程序之前对请求进行身份验证和授权 |
ResolveRequestCache |
当 ASP.NET 完成授权事件以使缓存模块从缓存中为请求提供服务时发生,从而跳过事件处理程序(例如某个页或 XML Web services)的执行 |
PostResolveRequestCache |
在 ASP.NET 跳过当前事件处理程序的执行并允许缓存模块满足来自缓存的请求时发生。)在 PostResolveRequestCache 事件之后、PostMapRequestHandler 事件之前创建一个事件处理程序(对应于请求 URL 的页 |
PostMapRequestHandler |
在 ASP.NET 已将当前请求映射到相应的事件处理程序时发生。
|
AcquireRequestState |
当 ASP.NET 获取与当前请求关联的当前状态(如会话状态)时发生。
|
PostAcquireRequestState |
在已获得与当前请求关联的请求状态(例如会话状态)时发生。
|
PreRequestHandlerExecute |
恰好在 ASP.NET 开始执行事件处理程序(例如,某页或某个 XML Web services)前发生。
|
PostRequestHandlerExecute |
在 ASP.NET 事件处理程序(例如,某页或某个 XML Web service)执行完毕时发生。
|
ReleaseRequestState
|
在 ASP.NET 执行完所有请求事件处理程序后发生。该事件将使状态模块保存当前状态数据。
|
PostReleaseRequestState
|
在 ASP.NET 已完成所有请求事件处理程序的执行并且请求状态数据已存储时发生。
|
UpdateRequestCache
|
当 ASP.NET 执行完事件处理程序以使缓存模块存储将用于从缓存为后续请求提供服务的响应时发生。
|
PostUpdateRequestCache
|
在 ASP.NET 完成缓存模块的更新并存储了用于从缓存中为后续请求提供服务的响应后,发生此事件。
|
LogRequest
|
在 ASP.NET 完成缓存模块的更新并存储了用于从缓存中为后续请求提供服务的响应后,发生此事件。 仅在 IIS 7.0 处于集成模式并且 .NET Framework 至少为 3.0 版本的情况下才支持此事件
|
PostLogRequest
|
在 ASP.NET 处理完 LogRequest 事件的所有事件处理程序后发生。 仅在 IIS 7.0 处于集成模式并且 .NET Framework 至少为 3.0 版本的情况下才支持此事件。
|
EndRequest
|
在 ASP.NET 响应请求时作为 HTTP 执行管线链中的最后一个事件发生。 在调用 CompleteRequest 方法时始终引发 EndRequest 事件。
|
写的可能不是十分详细,基本也差不多了,如果有什么不对的地方欢迎指正。