• ASP.NET Web API 框架研究 Controller创建过程与消息处理管道


      现在我们从代码角度来看下,从消息处理管道末尾是怎么创建出Controller实例的。消息处理管道末端是一个叫HttpRoutingDispatcher的处理器,其内部完成路由后 ,会把消息派送给其内部的一个消息处理器HttpControllerDispatcher来完成Controller实例创建。

    一、流程示意图

    二、代码说明

    我们先看下HttpControllerDispatcher代码,主要看下SendAsync方法:

    public class HttpControllerDispatcher : HttpMessageHandler
        {
            private readonly HttpConfiguration _configuration;
    
            private IExceptionLogger _exceptionLogger;
            private IExceptionHandler _exceptionHandler;
            private IHttpControllerSelector _controllerSelector;
    
            /// <summary>
            /// Initializes a new instance of the <see cref="HttpControllerDispatcher"/> class.
            /// </summary>
            public HttpControllerDispatcher(HttpConfiguration configuration)
            {
                if (configuration == null)
                {
                    throw Error.ArgumentNull("configuration");
                }
    
                _configuration = configuration;
            }
    
            /// <summary>
            /// Gets the <see cref="HttpConfiguration"/>.
            /// </summary>
            public HttpConfiguration Configuration
            {
                get { return _configuration; }
            }
    
            /// <remarks>This property is internal and settable only for unit testing purposes.</remarks>
            internal IExceptionLogger ExceptionLogger
            {
                get
                {
                    if (_exceptionLogger == null)
                    {
                        _exceptionLogger = ExceptionServices.GetLogger(_configuration);
                    }
    
                    return _exceptionLogger;
                }
                set
                {
                    _exceptionLogger = value;
                }
            }
    
            /// <remarks>This property is internal and settable only for unit testing purposes.</remarks>
            internal IExceptionHandler ExceptionHandler
            {
                get
                {
                    if (_exceptionHandler == null)
                    {
                        _exceptionHandler = ExceptionServices.GetHandler(_configuration);
                    }
    
                    return _exceptionHandler;
                }
                set
                {
                    _exceptionHandler = value;
                }
            }
    
            //从服务容器里直接获取默认的HttpControllerSelector
            private IHttpControllerSelector ControllerSelector
            {
                get
                {
                    if (_controllerSelector == null)
                    {
                        _controllerSelector = _configuration.Services.GetHttpControllerSelector();
                    }
    
                    return _controllerSelector;
                }
            }
    
          
            protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                if (request == null)
                {
                    throw Error.ArgumentNull("request");
                }
    
                ExceptionDispatchInfo exceptionInfo;
                HttpControllerContext controllerContext = null;
    
                try
                {
                    //1.通过IHttpControllerSelector获取HttpControllerDescriptor
                    HttpControllerDescriptor controllerDescriptor = ControllerSelector.SelectController(request);
                    if (controllerDescriptor == null)
                    {
                        return request.CreateErrorResponse(
                            HttpStatusCode.NotFound,
                            Error.Format(SRResources.ResourceNotFound, request.RequestUri),
                            SRResources.NoControllerSelected);
                    }
                    //2.HttpControllerDescriptor的CreateController方法创建出控制器实例
                    IHttpController controller = controllerDescriptor.CreateController(request);
                    if (controller == null)
                    {
                        return request.CreateErrorResponse(
                            HttpStatusCode.NotFound,
                            Error.Format(SRResources.ResourceNotFound, request.RequestUri),
                            SRResources.NoControllerCreated);
                    }
                    //准备参数ControllerContext
                    controllerContext = CreateControllerContext(request, controllerDescriptor, controller);
                    //3.直接执行控制器的ExecuteAsync,即抽象类ApiController里的ExecuteAsync方法
                    return await controller.ExecuteAsync(controllerContext, cancellationToken);
                }
                catch (OperationCanceledException)
                {
                    // Propogate the canceled task without calling exception loggers or handlers.
                    throw;
                }
                catch (HttpResponseException httpResponseException)
                {
                    return httpResponseException.Response;
                }
                catch (Exception exception)
                {
                    exceptionInfo = ExceptionDispatchInfo.Capture(exception);
                }
    
                Debug.Assert(exceptionInfo.SourceException != null);
    
                ExceptionContext exceptionContext = new ExceptionContext(
                    exceptionInfo.SourceException,
                    ExceptionCatchBlocks.HttpControllerDispatcher,
                    request)
                {
                    ControllerContext = controllerContext,
                };
    
                await ExceptionLogger.LogAsync(exceptionContext, cancellationToken);
                HttpResponseMessage response = await ExceptionHandler.HandleAsync(exceptionContext, cancellationToken);
    
                if (response == null)
                {
                    exceptionInfo.Throw();
                }
    
                return response;
            }
    
            private static HttpControllerContext CreateControllerContext(
                HttpRequestMessage request,
                HttpControllerDescriptor controllerDescriptor,
                IHttpController controller)
            {
                Contract.Assert(request != null);
                Contract.Assert(controllerDescriptor != null);
                Contract.Assert(controller != null);
    
                HttpConfiguration controllerConfiguration = controllerDescriptor.Configuration;
    
                // Set the controller configuration on the request properties
                HttpConfiguration requestConfig = request.GetConfiguration();
                if (requestConfig == null)
                {
                    request.SetConfiguration(controllerConfiguration);
                }
                else
                {
                    if (requestConfig != controllerConfiguration)
                    {
                        request.SetConfiguration(controllerConfiguration);
                    }
                }
    
                HttpRequestContext requestContext = request.GetRequestContext();
    
                // if the host doesn't create the context we will fallback to creating it.
                if (requestContext == null)
                {
                    requestContext = new RequestBackedHttpRequestContext(request)
                    {
                        // we are caching controller configuration to support per controller configuration.
                        Configuration = controllerConfiguration,
                    };
    
                    // if the host did not set a request context we will also set it back to the request.
                    request.SetRequestContext(requestContext);
                }
    
                return new HttpControllerContext(requestContext, request, controllerDescriptor, controller);
            }
    
            private static HttpConfiguration EnsureNonNull(HttpConfiguration configuration)
            {
                if (configuration == null)
                {
                    throw Error.ArgumentNull("configuration");
                }
    
                return configuration;
            }
        }

      从SendAsync方法可以知道,主要有三大关键代码:

      1、通过IHttpControllerSelector获取HttpControllerDescriptor
      HttpControllerDescriptor controllerDescriptor = ControllerSelector.SelectController(request);

      ControllerSelector是从服务容器里获取的默认实现DefaultHttpControllerSelector,回顾下里边的代码:

      

      由Lazy特点,触发InitializeControllerInfoCache方法

      

      

       进入HttpControllerTypeCache,读取缓存,由Lazy特点,触发InitializeCache

      

      通过AssemblieResolver和HttpControllerTypeResolver组件构建出合法的控制器类型列表

      

      执行HttpControllerTypeCache获取Cache后,根据其构建出控制器描述符缓存,SelectController方法直接从该缓存中获取最后的控制器描述符

      2、HttpControllerDescriptor的CreateController方法创建出控制器实例

       IHttpController controller = controllerDescriptor.CreateController(request);

      使用HttpControllerDescriptor的CreateController方法创建

       

      内部调用了组件DefaultHttpControllerActivator实现

      

            

           

      3、直接执行控制器实例的ExecuteAsync,即抽象类ApiController里的ExecuteAsync方法

      //准备参数ControllerContext
      controllerContext = CreateControllerContext(request, controllerDescriptor, controller);
      return await controller.ExecuteAsync(controllerContext, cancellationToken);

       到这里就进入ApiController 的ExecuteAsync

    //主要方法,创建控制器对象后,会调用ExecuteAsync方法,进行后续操作,由于还没讲控制器的创建,里边的逻辑以后再细说
            public virtual Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
            {
                if (_initialized)
                {
                    // 如果已经创建过该实例,就抛出异常,一个控制器实例,多次请求不能重复使用
                    throw Error.InvalidOperation(SRResources.CannotSupportSingletonInstance, typeof(ApiController).Name, typeof(IHttpControllerActivator).Name);
                }
    
                Initialize(controllerContext);
    
               
                if (Request != null)
                {
                    //先注册到待销毁集合,待请求完成后一起销毁改控制器实例
                    Request.RegisterForDispose(this);
                }
    
                HttpControllerDescriptor controllerDescriptor = controllerContext.ControllerDescriptor;
                ServicesContainer controllerServices = controllerDescriptor.Configuration.Services;
                //选择Action
                HttpActionDescriptor actionDescriptor = controllerServices.GetActionSelector().SelectAction(controllerContext);
                ActionContext.ActionDescriptor = actionDescriptor;
                if (Request != null)
                {
                    Request.SetActionDescriptor(actionDescriptor);
                }
    
                FilterGrouping filterGrouping = actionDescriptor.GetFilterGrouping();
    
                //ActionFilters
                IActionFilter[] actionFilters = filterGrouping.ActionFilters;
                //身份认证过滤器
                IAuthenticationFilter[] authenticationFilters = filterGrouping.AuthenticationFilters;
                //授权过滤器
                IAuthorizationFilter[] authorizationFilters = filterGrouping.AuthorizationFilters;
                //ExceptionFilters
                IExceptionFilter[] exceptionFilters = filterGrouping.ExceptionFilters;
    
                IHttpActionResult result = new ActionFilterResult(actionDescriptor.ActionBinding, ActionContext,
                    controllerServices, actionFilters);
                if (authorizationFilters.Length > 0)
                {
                    result = new AuthorizationFilterResult(ActionContext, authorizationFilters, result);
                }
                if (authenticationFilters.Length > 0)
                {
                    result = new AuthenticationFilterResult(ActionContext, this, authenticationFilters, result);
                }
                if (exceptionFilters.Length > 0)
                {
                    IExceptionLogger exceptionLogger = ExceptionServices.GetLogger(controllerServices);
                    IExceptionHandler exceptionHandler = ExceptionServices.GetHandler(controllerServices);
                    result = new ExceptionFilterResult(ActionContext, exceptionFilters, exceptionLogger, exceptionHandler,
                        result);
                }
                //执行IHttpActionResult的ExecuteAsync
                return result.ExecuteAsync(cancellationToken);
            }
  • 相关阅读:
    装饰
    统一软件开发过程之2:用例文本书写
    统一软件开发过程之1:创建领域模型
    工厂方法
    volatile
    中介者
    建造者
    C#委托,事件与回调函数
    控件资源嵌入
    装饰
  • 原文地址:https://www.cnblogs.com/shawnhu/p/8082440.html
Copyright © 2020-2023  润新知