现在我们从代码角度来看下,从消息处理管道末尾是怎么创建出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 > )
{
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);
}

ASP.NET Web API 框架研究 Controller创建过程与消息处理管道的更多相关文章

  1. ASP.NET Web API 框架研究 Controller创建 HttpController介绍

    对请求进行路由解析以及消息处理管道进行处理后,最后可以从HttpRequestMessage对象的属性字典中获取解析的路由数据,后边我们就可以根据其进行HttpController的创建,从前边几篇可 ...

  2. ASP.NET Web API 框架研究 Controller创建 HttpController 类型解析 选择 创建

    上一篇介绍了HttpController的一些细节,接下来说下HttpController 类型解析.选择和创建.生产HttpController实例的生产线如下图: 一.涉及的类及源码分析 涉及的类 ...

  3. ASP.NET Web API 框架研究 Controller实例的销毁

    我们知道项目中创建的Controller,如ProductController都继承自ApiController抽象类,其又实现了接口IDisposable,所以,框架中自动调用Dispose方法来释 ...

  4. ASP.NET Web API 框架研究 ASP.NET Web API 路由

    ASP.NET Web API 核心框架是一个独立的.抽象的消息处理管道,ASP.NET Web API有自己独立的路由系统,是消息处理管道的组成部分,其与ASP.NET路由系统有类似的设计,都能找到 ...

  5. ASP.NET Web API 框架研究 Action方法介绍

    在根据请求解析出匹配的Controller类型并创建实例后,要在该Controller类型中的众多Action方法中选择与请求匹配的那一个,并执行,然后返回响应. Action方法,其元数据,主要包括 ...

  6. ASP.NET Web API 框架研究 核心的消息处理管道

    ASP.NET Web API 的核心框架是一个由一组HttpMessageHandler有序组成的双工消息处理管道:寄宿监听到请求接受后,把消息传入该管道经过所有HttpMessageHandler ...

  7. ASP.NET Web API 框架研究 IoC容器 DependencyResolver

    一.概念 1.IoC(Inversion of Control),控制反转 即将依赖对象的创建和维护交给一个外部容器来负责,而不是应用本身.如,在类型A中需要使用类型B的实例,而B的实例的创建不是由A ...

  8. ASP.NET Web API 框架研究 服务容器 ServicesContainer

    ServicesContainer是一个服务的容器,可以理解为—个轻量级的IoC容器,其维护着一个服务接口类型与服务实例之间的映射关系,可以根据服务接口类型获取对应的服务实例.构成ASP.NET We ...

  9. ASP.NET Web API 框架研究 Self Host模式下的消息处理管道

    Self Host模式下的ASP.NET Web API与WCF非常相似,都可以寄宿在任意类型的托管应用程序中,宿主可以是Windows Form .WPF.控制台应用以及Windows Servic ...

随机推荐

  1. Android.HowToDesignPluginArchitectureInAndroidApp

    There is a tools called "dx", this tool can transfer Java Binary Code into Android Dalvik ...

  2. Java中的权限修饰符

    What:访问控制权限是可以设置代码的访问范围. Where:访问权限既可以修饰类中的属性,又可以修饰类中的方法,而public和default还可以修饰类. 在同一个java文件里,公有类有且仅有一 ...

  3. NC 6系初始化EJB

    6系开发时,调用远程接口去操作数据时,需先调用EJB. InvocationInfoProxy.getInstance().setUserDataSource(design); InvocationI ...

  4. Delphi、Lazarus保留字、关键字详解

    Delphi.Lazarus保留字.关键字详解 来自橙子,万一的博客以及其他地方 保留字:变量等标识符可以再使用: 关键字:有特定含义,不能再次重新定义: 修饰字:类似保留字的功能,也就是说可以重用 ...

  5. GCC编译的几个步骤

    参考资料: https://blog.csdn.net/czg13548930186/article/details/78331692 一个C/C++文件要经过预处理(preprocessing).编 ...

  6. 如果CocoaPods 导入的库需要修改代码

      如果经常要修改第三方框架的话,可以将需要修改的第三方库fork一份到自己的github,在里面做完修改之后,将podfile修改为: platform :ios, '7.0' pod '要导入的库 ...

  7. 编译sgbm_ros中遇到的问题

    出现的问题 这个会报错 1.解决方法是在文件sudo gedit /usr/local/cuda/include/crt/common_functions.h中注释掉如下 #define __CUDA ...

  8. Nodejs+Mongo+WebAPI

    Nodejs+Mongo+WebAPI集成 1.[ 目录]: |- models/bear.js |- node_modules/ |- express |- mongoose |- body-par ...

  9. oracle的常用99条语句

    1. select * from emp; 2. select empno, ename, job from emp; 3. select empno 编号, ename 姓名, job 工作 fro ...

  10. spring学习 十二 AspectJ-based的通知入门 带参数的通知

    第一步:编写通知类 package com.airplan.pojo; import org.aspectj.lang.ProceedingJoinPoint; public class Advice ...