zoukankan      html  css  js  c++  java
  • Asp.net Mvc 与 Web Api生命周期对比

     
    完整的生命周期比较复杂,对细节感兴趣的同学可购买老A的图书学习:传送门

     本文只简单讲述路由注册controller创建action选择的3个主逻辑线,其他的内容大家可自己阅读相应的代码

    先上二者单独的生命周期介绍文档:  mvc生命周期  ,   web api生命周期

     以下内容以vs创建的默认mvc 、webapi 项目为准分析,不足之处,敬请体谅

    Mvc

     Web Api(web host)

    1、路由注册、处理、解析对应handler

    UrlRoutingModule通过重载IHttpModule来接管mvc和webapi的处理

    以下为简要逻辑代码(删减了部分)

     1 protected virtual void Init(HttpApplication application) {
     2     application.PostResolveRequestCache += OnApplicationPostResolveRequestCache;
     3 }
     4 
     5 private void OnApplicationPostResolveRequestCache(object sender, EventArgs e) {
     6     HttpApplication app = (HttpApplication)sender;
     7     HttpContextBase context = new HttpContextWrapper(app.Context);
     8     PostResolveRequestCache(context);
     9 }
    10 
    11 public virtual void PostResolveRequestCache(HttpContextBase context) {
    12     // Match the incoming URL against the route table
    13     RouteData routeData = RouteCollection.GetRouteData(context);
    14 
    15     // If a route was found, get an IHttpHandler from the route's RouteHandler
    16     IRouteHandler routeHandler = routeData.RouteHandler;
    17 
    18     RequestContext requestContext = new RequestContext(context, routeData);
    19 
    20     IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
    21     if (httpHandler == null) {
    22         throw new InvalidOperationException(
    23             String.Format(
    24                 CultureInfo.CurrentUICulture,
    25                 SR.GetString(SR.UrlRoutingModule_NoHttpHandler),
    26                 routeHandler.GetType()));
    27     }
    28 
    29     // Remap IIS7 to our handler
    30     context.RemapHandler(httpHandler);
    31 }
    View Code

    逻辑为:从注册的RouteData中解析RouteHandler,然后再调用GetHttpHandler获取相应的IHttpHandler

    mvc中的HttpHandler是MvcHandler

    webapi中的是               HttpControllerHandler

    所以路由注册的目标是:注册+指定handler

    下面看下二者的不同

    //WebApiApplication.cs
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    //RouteConfig.cs routes.MapRoute( name:
    "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );

    RouteTable.Routes 作为注册入口,

    MapRoute中指定RouteHandlerMvcRouteHandler的处理器

    然后再获取IHttpHandler

    //MvcRouteHandler.cs
    protected
    virtual IHttpHandler GetHttpHandler(RequestContext requestContext) { requestContext.HttpContext.SetSessionStateBehavior(this.GetSessionStateBehavior(requestContext)); return (IHttpHandler) new MvcHandler(requestContext); }
    //WebApiApplication.cs
    GlobalConfiguration.Configure(WebApiConfig.Register);
    //WebApiConfig.cs
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );

    GlobalConfiguration.HttpConfiguration 作为注册入口,

    并在HostedHttpRoute中指定RouteHandlerHttpControllerRouteHandler

    然后再获取IHttpHandler

    //HttpControllerRouteHandler.cs
    protected
    virtual IHttpHandler GetHttpHandler(RequestContext requestContext) { return (IHttpHandler) new HttpControllerHandler(requestContext.RouteData);
    }

    2、创建Controller 

     为了方便理解逻辑,使用同步版本来描述,实际使用中,继承controller的都是使用一步版本

    在上一步已经获取到 MvcHandler,接着显式调用 IHttpHandler.ProcessRequest 方法

    void IHttpHandler.ProcessRequest(HttpContext httpContext)
    {
        this.ProcessRequest(httpContext);
    }
    protected virtual void ProcessRequest(HttpContext httpContext)
    {
        this.ProcessRequest((HttpContextBase) new HttpContextWrapper(httpContext));
    }
    protected internal virtual void ProcessRequest(HttpContextBase httpContext)
    {
        IController controller;
        IControllerFactory factory;
        this.ProcessRequestInit(httpContext, out controller, out factory); 
        try
        {
            controller.Execute(this.RequestContext);
        }
        finally
        {
            factory.ReleaseController(controller);
        }
    }
    private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
    {
        string requiredString = this.RequestContext.RouteData.GetRequiredString(nameof (controller));
        factory = this.ControllerBuilder.GetControllerFactory();
        controller = factory.CreateController(this.RequestContext, requiredString);
    }

     

    上述ProcessRequestInit方法内部,只展示了基本逻辑,

    通过ControllerFactory创建 Contrller,

    之后调用 Controller.Execute 执行Controller创建Action的逻辑

    同样,找到 HttpControllerHandler开始处理,

    web api在创建controller之前可对请求流做管道式处理,

    可在请求消息到达路由选择前提前加入处理逻辑

    //HttpTaskAsyncHandler.cs
    public abstract Task ProcessRequestAsync(HttpContext context);
    
    
    IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) {
        return TaskAsyncHelper.BeginTask(() => ProcessRequestAsync(context), cb, extraData);
    }
    
    void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) {
        TaskAsyncHelper.EndTask(result);
    }
    public override Task ProcessRequestAsync(HttpContext context)
    {
        return this.ProcessRequestAsyncCore((HttpContextBase) new HttpContextWrapper(context));
    }
    internal async Task ProcessRequestAsyncCore(HttpContextBase contextBase) { HttpRequestMessage request = contextBase.GetHttpRequestMessage() ?? HttpControllerHandler.ConvertRequest(contextBase); request.SetRouteData(this._routeData); CancellationToken cancellationToken = contextBase.Response.GetClientDisconnectedTokenWhenFixed(); HttpResponseMessage response = (HttpResponseMessage) null; try {
         //创建HttpMessageHandler管道,只有最后一个为 HttpMessageHandler衍生类,其余皆为子类DelegatingHandler的衍生类 response
    = await this._server.SendAsync(request, cancellationToken); await HttpControllerHandler.CopyResponseAsync(contextBase, request, response, HttpControllerHandler._exceptionLogger.Value, HttpControllerHandler._exceptionHandler.Value, cancellationToken); } catch (OperationCanceledException ex) { ... }
      ...
    }

    通过GlobalConfiguration.HttpConfiguration入口可配置自定义的HttpMessageHandler委托链,

    其中HttpServer是第一个被执行的HttpMessageHandler

    HttpRoutingDispatcher是最后一个,具体封装实现是在HttpServer.Initialize()中,如下:

    protected virtual void Initialize()
    {
        this._configuration.EnsureInitialized();
        this.InnerHandler = HttpClientFactory.CreatePipeline(this._dispatcher, (IEnumerable<DelegatingHandler>) this._configuration.MessageHandlers);
    }

    作为最后一个handler的HttpRoutingDispatcher在构造函数中默认指定HttpControllerDispatcher为处理handler

    HttpControllerDispatcher才是真正的controller创建入口

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        ...
        try
        {
        HttpControllerDescriptor controllerDescriptor = this.ControllerSelector.SelectController(request);
    
        IHttpController controller = controllerDescriptor.CreateController(request);
    
        controllerContext = HttpControllerDispatcher.CreateControllerContext(request, controllerDescriptor, controller);
        return await controller.ExecuteAsync(controllerContext, cancellationToken);
        }
        catch (OperationCanceledException ex)
        {
            ...
        }
    
        HttpResponseMessage response = await this.ExceptionHandler.HandleAsync(exceptionContext, cancellationToken);
    
        return response;
    }

      

    3、创建action

    //ControllerBase类中方法
    void IController.Execute(RequestContext requestContext)
    {
        this.Execute(requestContext);
    }
    protected virtual void Execute(RequestContext requestContext)
    {
        ...
        this.ExecuteCore();
    }
    //Controller类中方法
    protected override void ExecuteCore()
    {
        this.PossiblyLoadTempData();
        try
        {
            string actionName = Controller.GetActionName(this.RouteData);
            if (this.ActionInvoker.InvokeAction(this.ControllerContext, actionName))
                return;
            this.HandleUnknownAction(actionName);
        }
        finally
        {
            this.PossiblySaveTempData();
        }
    }

    对应的同步版本ControllerActionInvoker逻辑为:

    public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
    {
        ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);
        ActionDescriptor action = this.FindAction(controllerContext, controllerDescriptor, actionName);
    
       //5种过滤器 FilterInfo filters
    = this.GetFilters(controllerContext, action); try {
         //身份过滤器   AuthenticationContext authenticationContext
    = this.InvokeAuthenticationFilters(controllerContext, filters.AuthenticationFilters, action);   if (authenticationContext.Result != null)   {   AuthenticationChallengeContext challengeContext = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, action, authenticationContext.Result);   this.InvokeActionResult(controllerContext, challengeContext.Result ?? authenticationContext.Result);   }   else   {
           //权限过滤器   AuthorizationContext authorizationContext
    = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, action);   if (authorizationContext.Result != null)   {     AuthenticationChallengeContext challengeContext = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, action, authorizationContext.Result);     this.InvokeActionResult(controllerContext, challengeContext.Result ?? authorizationContext.Result);   }   else   {
             //action 过滤器     
    if (controllerContext.Controller.ValidateRequest)     ControllerActionInvoker.ValidateRequest(controllerContext);     IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, action);     ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, action, parameterValues);
        AuthenticationChallengeContext challengeContext
    = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, action, actionExecutedContext.Result);     this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, challengeContext.Result ?? actionExecutedContext.Result);   }   } } catch (Exception ex) {
         //异常过滤器 ExceptionContext exceptionContext
    = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, ex); if (!exceptionContext.ExceptionHandled) throw; else this.InvokeActionResult(controllerContext, exceptionContext.Result); } return true; }
     
    //ApiController.cs
    public
    virtual Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) { this.Initialize(controllerContext); ServicesContainer services = controllerContext.ControllerDescriptor.Configuration.Services; HttpActionDescriptor actionDescriptor = services.GetActionSelector().SelectAction(controllerContext); this.ActionContext.ActionDescriptor = actionDescriptor;   
    //4种过滤器 FilterGrouping filterGrouping
    = actionDescriptor.GetFilterGrouping(); IActionFilter[] actionFilters = filterGrouping.ActionFilters; IAuthenticationFilter[] authenticationFilters = filterGrouping.AuthenticationFilters; IAuthorizationFilter[] authorizationFilters = filterGrouping.AuthorizationFilters; IExceptionFilter[] exceptionFilters = filterGrouping.ExceptionFilters;
    IHttpActionResult innerResult
    = (IHttpActionResult) new ActionFilterResult(actionDescriptor.ActionBinding, this.ActionContext, services, actionFilters);
    if (authorizationFilters.Length > 0) innerResult = (IHttpActionResult) new AuthorizationFilterResult(this.ActionContext, authorizationFilters, innerResult);
    if (authenticationFilters.Length > 0) innerResult = (IHttpActionResult) new AuthenticationFilterResult(this.ActionContext, this, authenticationFilters, innerResult);
    if (exceptionFilters.Length > 0) { IExceptionLogger logger = ExceptionServices.GetLogger(services); IExceptionHandler handler = ExceptionServices.GetHandler(services); innerResult = (IHttpActionResult) new ExceptionFilterResult(this.ActionContext, exceptionFilters, logger, handler, innerResult); }
    return innerResult.ExecuteAsync(cancellationToken); }
       
       
  • 相关阅读:
    Supermap/Cesium 开发心得----获取三维视角的四至范围
    Supermap/Cesium 开发心得----定位
    GIS面试小知识点
    Oracle数据库小知识点整理
    利用 uDig 生成 GeoServer 可用的 SLD 渲染文件
    Geoserver设置style
    图片按宽高比1:1响应,窗口大小如何变化,图片宽高始终相等
    简单树
    递归渲染树
    div等高布局
  • 原文地址:https://www.cnblogs.com/tomkluas/p/8323613.html
Copyright © 2011-2022 走看看