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

  

一、涉及的类及源码分析

  涉及的类主要在程序集System.Web.Http中的Dispatcher下边,类如下图:

  

1、IAssembliesResolver DefaultAssembliesResolver

  AssembliesResolver为HttpController类型的解析提供了可选的程序集,即提供了实现了IHttpController接口的候选HttpController类型的程序集范围;所有AssembliesResolver都实现IAssembliesResolver,接口只有一个方法,如下

  1. public interface IAssembliesResolver
  2. {
  3. //提供解析的程序集范围,返回应用程序可用的程序集列表
  4. ICollection<Assembly> GetAssemblies();
  5. }

  默认实现是DefauItAssembliesResolver,DefauItAssembliesResolver在实现的GetAssembIies方法中直接返回当前应用程序域加载的所有程序集列表,代码如下

  1. public class DefaultAssembliesResolver : IAssembliesResolver
  2. {
  3. public virtual ICollection<Assembly> GetAssemblies()
  4. {
  5. return AppDomain.CurrentDomain.GetAssemblies().ToList();
  6. }
  7. }

  而服务接口IAssembliesResolver的服务实例DefauItAssembliesResolver,是在服务容器里注册的

  获取可以用扩展方法直接获取:

  

 

 2、IHttpControllerTypeResolver DefaultHttpControllerTypeResolver

  返回可供选择的HttpControllerType列表。

  前边的AssembIiesResolver对象为HttpController类型的解析提供了可供选择的程序集,而HttpControllerTypeResolver具体进行类型解析,其均实现了接口IHttpControllerTypeResolver,其只有一个方法GetControllerTypes,而且以IAssembIiesResolver为参数,提供类型程序集。如下:

  1. public interface IHttpControllerTypeResolver
  2. {
  3. //参数IAssembliesResolver提供解析的程序集
  4. ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver);
  5. }

  即根据提供的程序集参数,获取所有符合条件的HttpControllerType列表,现在还没解析完,后续还要从其中选择一个合适的,只是返回可供选择的列表,默认实现是DefaultHttpControllerTypeResolver。

  注意点:

  • 委托 Predicate<Type>,Func<Assembly, Type[]>这种函数式编程用法,把函数当属性和参数
  • 只是从多个指定程序集中返回可供选择的HttpControllerType列表,还不是最后解析出的类型
  • 判断HttpController类型有效规则,即外部可见 (IsVisibIe=true)的实例 (IsAbstract=false)类 (IsClass=true),直接或耆间接实现了接口IHttpController,类型名称必须以“Controller” 为后缀,但是不区分大小写 (即 可以使用 “controIler” 作为后缀 )。
  1. public class DefaultHttpControllerTypeResolver : IHttpControllerTypeResolver
  2. {
  3. //判断是否为有效Controller的委托,默认指定了IsControllerType,也可以在构造函数指定
  4. private readonly Predicate<Type> _isControllerTypePredicate;
  5. //从程序集获取Type[]的委托,可以直接属性设置
  6. private Func<Assembly, Type[]> _getTypesFunc = GetTypes;
  7.  
  8. //构造函数,可以指定一个委托来判断是不是控制器类型,默认使用下边的IsControllerType
  9. public DefaultHttpControllerTypeResolver()
  10. : this(IsControllerType)
  11. {
  12. }
  13.  
  14. //构造函数,可以指定一个委托来判断是不是控制器类型
  15. public DefaultHttpControllerTypeResolver(Predicate<Type> predicate)
  16. {
  17. if (predicate == null)
  18. {
  19. throw Error.ArgumentNull("predicate");
  20. }
  21.  
  22. _isControllerTypePredicate = predicate;
  23. }
  24.  
  25. //只读,否为有效Controller的委托
  26. protected internal virtual Predicate<Type> IsControllerTypePredicate
  27. {
  28. get { return _isControllerTypePredicate; }
  29. }
  30.  
  31. //默认的用来判断是否是控制器的委托predicate
  32. internal static bool IsControllerType(Type t)
  33. {
  34. Contract.Assert(t != null);
  35. return
  36. t != null &&
  37. t.IsClass &&
  38. t.IsVisible &&
  39. !t.IsAbstract &&
  40. typeof(IHttpController).IsAssignableFrom(t) &&
  41. HasValidControllerName(t);
  42. }
  43.  
  44. //返回可用的控制器列表
  45. public virtual ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver)
  46. {
  47. if (assembliesResolver == null)
  48. {
  49. throw Error.ArgumentNull("assembliesResolver");
  50. }
  51.  
  52. List<Type> result = new List<Type>();
  53.  
  54. // 从assembliesResolver获取所有程序集
  55. ICollection<Assembly> assemblies = assembliesResolver.GetAssemblies();
  56. //遍历每个程序集
  57. foreach (Assembly assembly in assemblies)
  58. {
  59. Type[] exportedTypes = null;
  60. if (assembly == null || assembly.IsDynamic)
  61. {
  62. // 空或动态程序集就继续下个程序集,不操作当前程序集
  63. continue;
  64. }
  65.  
  66. try
  67. {
  68. //从程序集中获取Type[]
  69. exportedTypes = _getTypesFunc(assembly);
  70. }
  71. catch (ReflectionTypeLoadException ex)
  72. {
  73. exportedTypes = ex.Types;
  74. }
  75. catch
  76. {
  77. //忽略异常,继续解析,不影响最后结果,除非找不到NOT FOUND
  78. continue;
  79. }
  80.  
  81. if (exportedTypes != null)
  82. {
  83. //从Type[]中把有效的ControllerType存放到结果列表中
  84. result.AddRange(exportedTypes.Where(x => TypeIsVisible(x) && IsControllerTypePredicate(x)));
  85. }
  86. }
  87.  
  88. return result;
  89. }
  90.  
  91. //默认使用的从程序集获取Type[]
  92. internal static Type[] GetTypes(Assembly assembly)
  93. {
  94. return assembly.GetTypes();
  95. }
  96.  
  97. // 要以Controller结尾,但不能就是Controller,因为路由解析的控制器也不会为空
  98. internal static bool HasValidControllerName(Type controllerType)
  99. {
  100. Contract.Assert(controllerType != null);
  101. string controllerSuffix = DefaultHttpControllerSelector.ControllerSuffix;
  102. return controllerType.Name.Length > controllerSuffix.Length && controllerType.Name.EndsWith(controllerSuffix, StringComparison.OrdinalIgnoreCase);
  103. }
  104.  
  105. //设置从程序集获取Type[]的委托
  106. internal void SetGetTypesFunc(Func<Assembly, Type[]> getTypesFunc)
  107. {
  108. _getTypesFunc = getTypesFunc;
  109. }
  110.  
  111. private static bool TypeIsVisible(Type type)
  112. {
  113. //IsVisible是不是可以由程序集代码外访问
  114. return (type != null && type.IsVisible);
  115. }
  116. }

  

  其也可以通过ServicesContainer扩展方法直接获取:

  

3、HttpControllerTypeCache

  用来缓存反射出来的HttpControllerType,提高性能,是对HttpControllerTypeResolver解析出来的HttpController类型列表的缓存。

  缓存是一个Dictionary<string, ILookup<string, Type>>字典类型,Key为去除Controller后的部分,不区分大小写,如ProductController,Key为"Producct",Value为一个 ILookup<string, Type>类型,其Key可以重复,Key为控制器所在的命名空间,如ProductController所在命名空间"MyNameSpace",Value为具体的控制器类型如"ProductController"。

  注意:

  相同名称的控制器可能存在不同程序集和不同命名空间下

  1. internal sealed class HttpControllerTypeCache
  2. {
  3. private readonly HttpConfiguration _configuration;
  4. //惰性加载,缓存,Key为控制器名称出去Controller的部分(不区分大小写),
  5. //Value为一个ILookup<string, Type>,其Key可以重复,为控制所在的命名空间,Value为对应的控制器类型
  6. //相同名称的控制器可能存在不同程序集和不同命名空间下
  7. private readonly Lazy<Dictionary<string, ILookup<string, Type>>> _cache;
  8.  
  9. public HttpControllerTypeCache(HttpConfiguration configuration)
  10. {
  11. if (configuration == null)
  12. {
  13. throw Error.ArgumentNull("configuration");
  14. }
  15.  
  16. _configuration = configuration;
  17. _cache = new Lazy<Dictionary<string, ILookup<string, Type>>>(InitializeCache);
  18. }
  19.  
  20. //由于使用Lazy,调用该属性时候,才调用下边的InitializeCache
  21. internal Dictionary<string, ILookup<string, Type>> Cache
  22. {
  23. get { return _cache.Value; }
  24. }
  25.  
  26. //根据控制器名称获取可选的ControllerType列表,从缓存读取
  27. public ICollection<Type> GetControllerTypes(string controllerName)
  28. {
  29. if (String.IsNullOrEmpty(controllerName))
  30. {
  31. throw Error.ArgumentNullOrEmpty("controllerName");
  32. }
  33.  
  34. HashSet<Type> matchingTypes = new HashSet<Type>();
  35.  
  36. ILookup<string, Type> namespaceLookup;
  37. if (_cache.Value.TryGetValue(controllerName, out namespaceLookup))
  38. {
  39. foreach (var namespaceGroup in namespaceLookup)
  40. {
  41. matchingTypes.UnionWith(namespaceGroup);
  42. }
  43. }
  44.  
  45. return matchingTypes;
  46. }
  47.  
  48. //初始化缓存
  49. private Dictionary<string, ILookup<string, Type>> InitializeCache()
  50. {
  51. //获取AssembliesResolver服务实例
  52. IAssembliesResolver assembliesResolver = _configuration.Services.GetAssembliesResolver();
  53. //获取ControllersResolver服务实例
  54. IHttpControllerTypeResolver controllersResolver = _configuration.Services.GetHttpControllerTypeResolver();
  55. //调用ControllersResolver.GetControllerTypes以assembliesResolver为参数获取ControllerType列表
  56. ICollection<Type> controllerTypes = controllersResolver.GetControllerTypes(assembliesResolver);
  57. //先对解析出来的ControllerType列表按照ControllerType去除Controller后的名称分组,不区分大小写(OrdinalIgnoreCase)
  58. var groupedByName = controllerTypes.GroupBy(
  59. t => t.Name.Substring(, t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length),
  60. StringComparer.OrdinalIgnoreCase);
  61. //再转换成Dictionary<string, ILookup<string, Type>>缓存结构
  62. return groupedByName.ToDictionary(
  63. g => g.Key,
  64. g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase),
  65. StringComparer.OrdinalIgnoreCase);
  66. }
  67. }

4、IHttpControllerSelector DefaultHttpControllerSelector

  HttpControllerTypeResolver只是解析出所有合法的ControllerType列表,接下来要根据请求选择出匹配的HttpController类型。

  通过HttpControllerSelector来完成,其都实现接口IHttpControllerSelector,其主要有两个方法,如下:

  1. public interface IHttpControllerSelector
  2. {
  3. //根据请求选择一个匹配的控制器对应的描述符
  4. HttpControllerDescriptor SelectController(HttpRequestMessage request);
  5.  
  6. //返回描述所有HttpController类型的HttpControllerDescriptor对象与对应的HttpController名称之间的映射夫系
  7. IDictionary<string, HttpControllerDescriptor> GetControllerMapping();
  8. }

  同前边,默认实现DefaultHttpControllerSelector,也是是在服务容器里注册的,且同

  

  

  主要逻辑:

  • 控制器名称获取,不管Web Host还是Self Host路由解析数据最后都是放在HttpRequestMessage的属性字典中,所以先从请求中获取路由数据,再得到controller名称。如果路由变量中不存在名为controller的数据,或者程序集不存在或存在多个ControllerType,都会抛出异常
  • 丢弃在不同命名空间有多个匹配结果的控制器,比如,对于product名称的控制器,在A名称空间和B命名空间都有ProductController,由于系统不知道激活哪一个,所以采用的策略是两个都丢弃。这个逻辑在方法GetControllerMapping()
  • 系统会对GetControllerMapping结果缓存,我们在HttpControllerTypeResolver阶段解析出来的ControllerType在不同命名空间中存在多个匹配的控制器,所以采用Dictionary<string, ILookup<string, Type>>缓存,而GetControllerMapping返回的是IDictionary<string, HttpControllerDescriptor>类型,会丢弃上一点中的重复的控制器,返回的都是唯一的结果
  • 有两个缓存结构,一个是HttpControllerTypeCache 存放了所有合法的ControllerType,另一个是Lazy<ConcurrentDictionary<string, HttpControllerDescriptor>> _controllerInfoCache,它是根据前者构建出来的
  • 编程技巧,使用Lazy,Lazy<ConcurrentDictionary<string, HttpControllerDescriptor>> _controllerInfoCache,在从缓存_controllerInfoCache里读取数据时候,才去构建缓存内容,详细见代码注释
  1. public class DefaultHttpControllerSelector : IHttpControllerSelector
  2. {
  3. public static readonly string ControllerSuffix = "Controller";
  4.  
  5. private const string ControllerKey = "controller";
  6.  
  7. private readonly HttpConfiguration _configuration;
  8. //ControllerType缓存
  9. private readonly HttpControllerTypeCache _controllerTypeCache;
  10. private readonly Lazy<ConcurrentDictionary<string, HttpControllerDescriptor>> _controllerInfoCache;
  11.  
  12. public DefaultHttpControllerSelector(HttpConfiguration configuration)
  13. {
  14. if (configuration == null)
  15. {
  16. throw Error.ArgumentNull("configuration");
  17. }
  18. //Lazy惰性加载,用到_controllerInfoCache时候才去执行InitializeControllerInfoCache,进行缓存数据构建
  19. _controllerInfoCache = new Lazy<ConcurrentDictionary<string, HttpControllerDescriptor>>(InitializeControllerInfoCache);
  20. _configuration = configuration;
  21. _controllerTypeCache = new HttpControllerTypeCache(_configuration);
  22. }
  23.  
  24. //从请求中匹配指定控制器名称的控制器描述符号,从缓存中读取,缓存构建时机是在读取缓存时候,使用Lazy实现
  25. public virtual HttpControllerDescriptor SelectController(HttpRequestMessage request)
  26. {
  27. if (request == null)
  28. {
  29. throw Error.ArgumentNull("request");
  30. }
  31.  
  32. IHttpRouteData routeData = request.GetRouteData();
  33. HttpControllerDescriptor controllerDescriptor;
  34. if (routeData != null)
  35. {
  36. //先按特性路由(以后再说)解析,如果解析出数据,就直接返回
  37. controllerDescriptor = GetDirectRouteController(routeData);
  38. if (controllerDescriptor != null)
  39. {
  40. return controllerDescriptor;
  41. }
  42. }
  43. //非特性路由则
  44. //从HttpRequestMessage属性字典中获取控制器名称,获取不到就NotFound
  45. string controllerName = GetControllerName(request);
  46. if (String.IsNullOrEmpty(controllerName))
  47. {
  48. throw new HttpResponseException(request.CreateErrorResponse(
  49. HttpStatusCode.NotFound,
  50. Error.Format(SRResources.ResourceNotFound, request.RequestUri),
  51. Error.Format(SRResources.ControllerNameNotFound, request.RequestUri)));
  52. }
  53. //从控制器描述符缓存中获取,找到就直接返回,在此Lazy惰性加载,才去执行InitializeControllerInfoCache,进行缓存数据构建
  54. if (_controllerInfoCache.Value.TryGetValue(controllerName, out controllerDescriptor))
  55. {
  56. return controllerDescriptor;
  57. }
  58.  
  59. //找不到就根据实际情况,抛出不同异常
  60. ICollection<Type> matchingTypes = _controllerTypeCache.GetControllerTypes(controllerName);
  61.  
  62. // ControllerInfoCache is already initialized.
  63. Contract.Assert(matchingTypes.Count != );
  64. //根据不同原因创建不同类型异常
  65. if (matchingTypes.Count == )
  66. {
  67. // 没有匹配
  68. throw new HttpResponseException(request.CreateErrorResponse(
  69. HttpStatusCode.NotFound,
  70. Error.Format(SRResources.ResourceNotFound, request.RequestUri),
  71. Error.Format(SRResources.DefaultControllerFactory_ControllerNameNotFound, controllerName)));
  72. }
  73. else
  74. {
  75. // 匹配多个类型
  76. throw CreateAmbiguousControllerException(request.GetRouteData().Route, controllerName, matchingTypes);
  77. }
  78. }
  79.  
  80. public virtual IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
  81. {
  82. return _controllerInfoCache.Value.ToDictionary(c => c.Key, c => c.Value, StringComparer.OrdinalIgnoreCase);
  83. }
  84.  
  85. //从HttpRequestMessage的属性字典中获取控制器名称
  86. public virtual string GetControllerName(HttpRequestMessage request)
  87. {
  88. if (request == null)
  89. {
  90. throw Error.ArgumentNull("request");
  91. }
  92. //先从HttpRequestMessage的属性字典中获取路由数据
  93. IHttpRouteData routeData = request.GetRouteData();
  94. if (routeData == null)
  95. {
  96. return null;
  97. }
  98.  
  99. // TryGetValue获取key为controller的路由变量值
  100. string controllerName = null;
  101. routeData.Values.TryGetValue(ControllerKey, out controllerName);
  102. return controllerName;
  103. }
  104.  
  105. //特性路由逻辑以后再说
  106. private static HttpControllerDescriptor GetDirectRouteController(IHttpRouteData routeData)
  107. {
  108. CandidateAction[] candidates = routeData.GetDirectRouteCandidates();
  109. if (candidates != null)
  110. {
  111. // Set the controller descriptor for the first action descriptor
  112. Contract.Assert(candidates.Length > );
  113. Contract.Assert(candidates[].ActionDescriptor != null);
  114.  
  115. HttpControllerDescriptor controllerDescriptor = candidates[].ActionDescriptor.ControllerDescriptor;
  116.  
  117. // Check that all other candidate action descriptors share the same controller descriptor
  118. for (int i = ; i < candidates.Length; i++)
  119. {
  120. CandidateAction candidate = candidates[i];
  121. if (candidate.ActionDescriptor.ControllerDescriptor != controllerDescriptor)
  122. {
  123. // We've found an ambiguity (multiple controllers matched)
  124. throw CreateDirectRouteAmbiguousControllerException(candidates);
  125. }
  126. }
  127.  
  128. return controllerDescriptor;
  129. }
  130.  
  131. return null;
  132. }
  133.  
  134. private static Exception CreateDirectRouteAmbiguousControllerException(CandidateAction[] candidates)
  135. {
  136. Contract.Assert(candidates != null);
  137. Contract.Assert(candidates.Length > );
  138.  
  139. HashSet<Type> matchingTypes = new HashSet<Type>();
  140. for (int i = ; i < candidates.Length; i++)
  141. {
  142. matchingTypes.Add(candidates[i].ActionDescriptor.ControllerDescriptor.ControllerType);
  143. }
  144.  
  145. // we need to generate an exception containing all the controller types
  146. StringBuilder typeList = new StringBuilder();
  147. foreach (Type matchedType in matchingTypes)
  148. {
  149. typeList.AppendLine();
  150. typeList.Append(matchedType.FullName);
  151. }
  152.  
  153. return Error.InvalidOperation(SRResources.DirectRoute_AmbiguousController, typeList, Environment.NewLine);
  154. }
  155.  
  156. private static Exception CreateAmbiguousControllerException(IHttpRoute route, string controllerName, ICollection<Type> matchingTypes)
  157. {
  158. Contract.Assert(route != null);
  159. Contract.Assert(controllerName != null);
  160. Contract.Assert(matchingTypes != null);
  161.  
  162. // Generate an exception containing all the controller types
  163. StringBuilder typeList = new StringBuilder();
  164. foreach (Type matchedType in matchingTypes)
  165. {
  166. typeList.AppendLine();
  167. typeList.Append(matchedType.FullName);
  168. }
  169.  
  170. string errorMessage = Error.Format(SRResources.DefaultControllerFactory_ControllerNameAmbiguous_WithRouteTemplate, controllerName, route.RouteTemplate, typeList, Environment.NewLine);
  171. return new InvalidOperationException(errorMessage);
  172. }
  173.  
  174. //初始化构建ConcurrentDictionary<string, HttpControllerDescriptor>缓存,根据Dictionary<string, ILookup<string, Type>>类型 列表缓存
  175. private ConcurrentDictionary<string, HttpControllerDescriptor> InitializeControllerInfoCache()
  176. {
  177. var result = new ConcurrentDictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase);
  178. //由于同一控制器名称在不同命名空间中存在多个控制器类型,所以要去掉重复的,用来记录重复的Key
  179. var duplicateControllers = new HashSet<string>();
  180. //先从控制器类型列表中缓存中获取控制器类型列表
  181. Dictionary<string, ILookup<string, Type>> controllerTypeGroups = _controllerTypeCache.Cache;
  182.  
  183. //遍历
  184. foreach (KeyValuePair<string, ILookup<string, Type>> controllerTypeGroup in controllerTypeGroups)
  185. {
  186. string controllerName = controllerTypeGroup.Key;
  187.  
  188. foreach (IGrouping<string, Type> controllerTypesGroupedByNs in controllerTypeGroup.Value)
  189. {
  190. foreach (Type controllerType in controllerTypesGroupedByNs)
  191. {
  192. if (result.Keys.Contains(controllerName))
  193. {
  194. //有重复就记录在重复集合里,待移除处理
  195. duplicateControllers.Add(controllerName);
  196. break;
  197. }
  198. else
  199. {
  200. //new HttpControllerDescriptor
  201. result.TryAdd(controllerName, new HttpControllerDescriptor(_configuration, controllerName, controllerType));
  202. }
  203. }
  204. }
  205. }
  206. //去掉有重复的匹配控制器的数据
  207. foreach (string duplicateController in duplicateControllers)
  208. {
  209. HttpControllerDescriptor descriptor;
  210. result.TryRemove(duplicateController, out descriptor);
  211. }
  212.  
  213. return result;
  214. }
  215. }

 5、IHttpControllerActivator DefaultHttpControllerActivator

  通过HttpControllerTypeResolver解析得到请求(controller名称)对应的控制器描述符(HttpControllerDescriptor)后,通过HttpControllerActivator根据控制器描述符最终创建出HttpController实例,其都实现接口IHttpControllerActivator ,其定义如下:

  1. public interface IHttpControllerActivator
  2. {
  3. //根据HttpControllerDescriptor创建出IHttpController
  4. IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType);
  5. }

  DefaultHttpControllerActivator是默认实现,其配置同前边几个,不再赘述

  主要逻辑:

  • 在Create方法中,如果dependency resolver可以解析返回,就直接返回,否则就用创建委托activator来执行创建,而创建委托activator可以缓存到本地缓存和controllerDescriptor.Properties cache缓存,由上一篇可以知道,默认的IoC容器是EmptyResolver,所以dependency resolver都是返回空,所以每次都是通过反射创建实例。
  • activator通过反射来创建,在第一点中缓存的是创建对象的委托,而不是HttpController实例,其每次都是重新创建,所以对于多个针对相同的HttpControlIer类型的请求来说,最终创建的HttpController实例都是不同的
  1. public class DefaultHttpControllerActivator : IHttpControllerActivator
  2. {
  3. //缓存HttpControllerDescriptor对应的创建委托
  4. private Tuple<HttpControllerDescriptor, Func<IHttpController>> _fastCache;
  5. private object _cacheKey = new object();
  6.  
  7. //核心创建方法,如果dependency resolver可以解析返回,就直接返回,否则就用创建委托activator来执行创建,
  8. //而创建委托activator可以缓存到本地缓存和controllerDescriptor.Properties cache缓存
  9. public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
  10. {
  11. if (request == null)
  12. {
  13. throw Error.ArgumentNull("request");
  14. }
  15.  
  16. if (controllerDescriptor == null)
  17. {
  18. throw Error.ArgumentNull("controllerDescriptor");
  19. }
  20.  
  21. if (controllerType == null)
  22. {
  23. throw Error.ArgumentNull("controllerType");
  24. }
  25.  
  26. try
  27. {
  28. Func<IHttpController> activator;
  29.  
  30. //如果没有定义本地快速缓存
  31. if (_fastCache == null)
  32. {
  33. IHttpController controller = GetInstanceOrActivator(request, controllerType, out activator);
  34. if (controller != null)
  35. {
  36. //这里返回的是dependency resolver中有定义时候,定义的Controller实例
  37. return controller;
  38. }
  39. else
  40. {
  41. //初始化创建一个本地缓存cacheItem
  42. Tuple<HttpControllerDescriptor, Func<IHttpController>> cacheItem = Tuple.Create(controllerDescriptor, activator);
  43. Interlocked.CompareExchange(ref _fastCache, cacheItem, null);
  44. }
  45. }
  46. else if (_fastCache.Item1 == controllerDescriptor)
  47. {
  48. // 如果有定义本地快速缓存,而且匹配controllerDescriptor key就直接返回
  49. activator = _fastCache.Item2;
  50. }
  51. else
  52. {
  53. // 如果有定义本地快速缓存,没有匹配controllerDescriptor key,就从controllerDescriptor.Properties cache中获取创建委托
  54. object value;
  55. if (controllerDescriptor.Properties.TryGetValue(_cacheKey, out value))
  56. {
  57. activator = (Func<IHttpController>)value;
  58. }
  59. else
  60. {
  61. IHttpController controller = GetInstanceOrActivator(request, controllerType, out activator);
  62. if (controller != null)
  63. {
  64. //这里返回的是dependency resolver中有定义时候,定义的Controller实例
  65. return controller;
  66. }
  67. else
  68. {
  69. //添加进HttpControllerDescriptor.Properties cache
  70. controllerDescriptor.Properties.TryAdd(_cacheKey, activator);
  71. }
  72. }
  73. }
  74. //执行创建委托,创建实例
  75. return activator();
  76. }
  77. catch (Exception ex)
  78. {
  79. throw Error.InvalidOperation(ex, SRResources.DefaultControllerFactory_ErrorCreatingController, controllerType.Name);
  80. }
  81. }
  82.  
  83. // 返回控制器实例如果在dependency resolver得到就直接返回,否则通过反射创建
  84. private static IHttpController GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, out Func<IHttpController> activator)
  85. {
  86. Contract.Assert(request != null);
  87. Contract.Assert(controllerType != null);
  88.  
  89. // 如果dependency resolver可以直接返回controller就直接返回使用
  90. IHttpController instance = (IHttpController)request.GetDependencyScope().GetService(controllerType);
  91. if (instance != null)
  92. {
  93. activator = null;
  94. return instance;
  95. }
  96.  
  97. //如果dependency resolver没有定义,就返回通过反射直接创建的委托
  98. activator = TypeActivator.Create<IHttpController>(controllerType);
  99. return null;
  100. }
  101. }

 二、自定义扩展组件HttpControllerActivator

  从前边IHttpControllerActivator那节知道,每次创建实例都是通过反射完成的,因为默认情况下的IoC容器是EmptyResolver,所以dependency resolver都是返回空,根据代码可以知道,都是通过反射来完成,我们可以通过重新实现IHttpControllerActivator,把服务容器里默认定义的DefaultHttpControllerActivator替换掉,替换掉EmptyResolver的方式,上一篇已经说过。

  1. public class UnityHttpControllerActivator : IHttpControllerActivator
  2. {
  3. public IUnityContainer UnityContainer { get; private set; }
  4.  
  5. public UnityHttpControllerActivator(IUnityContainer unityContainer)
  6. {
  7. this.UnityContainer = unityContainer;
  8. }
  9.  
  10. public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
  11. {
  12. return (IHttpController)this.UnityContainer.Resolve(controllerType);
  13. }
  14. }

  注册:

  1. UnityContainer unityContainer = new UnityContainer();
  2. GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator),new UnityHttpControllerActivator(unityContainer));

ASP.NET Web API 框架研究 Controller创建 HttpController 类型解析 选择 创建的更多相关文章

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

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

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

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

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

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

  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. iOS.FBTweak

    FBTweak的源码分析 1. FBTweak提供了以下功能 A): 可以动态的修改某个变量的值,这些变量的类型包括: ... B): 可以以plist的形式将Tweak以key-value的形式进行 ...

  2. UIDataPicker 时间选择器

    自用时间选择器 @interface ViewController () { UILabel *cityLabel; UIDatePicker *datePicker; } //@property(n ...

  3. [RF] Robot Framework新手干货(转载)

    Robot Framework用法总结 Robot Framework完整流程学习系列一 Robotframework自动化新手常见问题总结--(基础篇)

  4. Spring 注解原理(三)@Qualifier @Value

    Spring 注解原理(三)@Qualifier @Value Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) 一.Aut ...

  5. Maximum Size Subarray Sum Equals k LT325

    Given an array nums and a target value k, find the maximum length of a subarray that sums to k. If t ...

  6. java 内存, 类加载g

    1. java 内存区域 方法区 虚拟机栈 本地方法栈 堆 程序计数器 其中 :  方法区  和 堆 是所有线程共享的 , 其他是线程隔离的 1.  程序计数器 : 可以看做是当前线程所执行的字节码的 ...

  7. maven mirror , profile , snapshot 和release

    1. settings.xml 配置的mirror <mirrors> <mirror> <id>Nexus</id> <name>nexu ...

  8. velocity 框架

    Java模板引擎 Velocity是一个基于java的模板引擎(template engine).它允许任何人仅仅使用简单的模板语言(template language)来引用由java代码定义的对象 ...

  9. 通过flask中的Response返回json数据

    使用flask的过程中,发现有时需要生成一个Response并返回.网上查了查,看了看源码,找到了两种办法: from flask import Response, json Response(jso ...

  10. python学习 day19 (3月26日)----(对象组合)

    深谙:非常透彻地了解:熟悉内中情形.谙,读作‘ān’ 熟悉. 1.面向对象作用:规划了代码中的函数处理的是哪一类问题 解决了传参的问题 方便扩展 方便重用 2.类的定义和使用类当中有哪些成员 ''' ...