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);
        }
原文地址:https://www.cnblogs.com/shawnhu/p/8082440.html