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

时间:2021-09-20 16:17:52

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

一、流程示意图

ASP.NET Web API 框架研究 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,回顾下里边的代码:

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

  由Lazy特点,触发InitializeControllerInfoCache方法

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

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

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

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

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

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

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

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

   IHttpController controller = controllerDescriptor.CreateController(request);

  使用HttpControllerDescriptor的CreateController方法创建

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

  内部调用了组件DefaultHttpControllerActivator实现

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

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

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

  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 > )
{
result = new AuthorizationFilterResult(ActionContext, authorizationFilters, result);
}
if (authenticationFilters.Length > )
{
result = new AuthenticationFilterResult(ActionContext, this, authenticationFilters, result);
}
if (exceptionFilters.Length > )
{
IExceptionLogger exceptionLogger = ExceptionServices.GetLogger(controllerServices);
IExceptionHandler exceptionHandler = ExceptionServices.GetHandler(controllerServices);
result = new ExceptionFilterResult(ActionContext, exceptionFilters, exceptionLogger, exceptionHandler,
result);
}
//执行IHttpActionResult的ExecuteAsync
return result.ExecuteAsync(cancellationToken);
}