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

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

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

一、涉及的类及源码分析

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

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

1、IAssembliesResolver DefaultAssembliesResolver

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

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

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

  public class DefaultAssembliesResolver : IAssembliesResolver
{
public virtual ICollection<Assembly> GetAssemblies()
{
return AppDomain.CurrentDomain.GetAssemblies().ToList();
}
}

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

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

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

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

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

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

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

 2、IHttpControllerTypeResolver DefaultHttpControllerTypeResolver

  返回可供选择的HttpControllerType列表。

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

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

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

  注意点:

  • 委托 Predicate<Type>,Func<Assembly, Type[]>这种函数式编程用法,把函数当属性和参数
  • 只是从多个指定程序集中返回可供选择的HttpControllerType列表,还不是最后解析出的类型
  • 判断HttpController类型有效规则,即外部可见 (IsVisibIe=true)的实例 (IsAbstract=false)类 (IsClass=true),直接或耆间接实现了接口IHttpController,类型名称必须以“Controller” 为后缀,但是不区分大小写 (即 可以使用 “controIler” 作为后缀 )。
public class DefaultHttpControllerTypeResolver : IHttpControllerTypeResolver
{
//判断是否为有效Controller的委托,默认指定了IsControllerType,也可以在构造函数指定
private readonly Predicate<Type> _isControllerTypePredicate;
//从程序集获取Type[]的委托,可以直接属性设置
private Func<Assembly, Type[]> _getTypesFunc = GetTypes; //构造函数,可以指定一个委托来判断是不是控制器类型,默认使用下边的IsControllerType
public DefaultHttpControllerTypeResolver()
: this(IsControllerType)
{
} //构造函数,可以指定一个委托来判断是不是控制器类型
public DefaultHttpControllerTypeResolver(Predicate<Type> predicate)
{
if (predicate == null)
{
throw Error.ArgumentNull("predicate");
} _isControllerTypePredicate = predicate;
} //只读,否为有效Controller的委托
protected internal virtual Predicate<Type> IsControllerTypePredicate
{
get { return _isControllerTypePredicate; }
} //默认的用来判断是否是控制器的委托predicate
internal static bool IsControllerType(Type t)
{
Contract.Assert(t != null);
return
t != null &&
t.IsClass &&
t.IsVisible &&
!t.IsAbstract &&
typeof(IHttpController).IsAssignableFrom(t) &&
HasValidControllerName(t);
} //返回可用的控制器列表
public virtual ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver)
{
if (assembliesResolver == null)
{
throw Error.ArgumentNull("assembliesResolver");
} List<Type> result = new List<Type>(); // 从assembliesResolver获取所有程序集
ICollection<Assembly> assemblies = assembliesResolver.GetAssemblies();
//遍历每个程序集
foreach (Assembly assembly in assemblies)
{
Type[] exportedTypes = null;
if (assembly == null || assembly.IsDynamic)
{
// 空或动态程序集就继续下个程序集,不操作当前程序集
continue;
} try
{
//从程序集中获取Type[]
exportedTypes = _getTypesFunc(assembly);
}
catch (ReflectionTypeLoadException ex)
{
exportedTypes = ex.Types;
}
catch
{
//忽略异常,继续解析,不影响最后结果,除非找不到NOT FOUND
continue;
} if (exportedTypes != null)
{
//从Type[]中把有效的ControllerType存放到结果列表中
result.AddRange(exportedTypes.Where(x => TypeIsVisible(x) && IsControllerTypePredicate(x)));
}
} return result;
} //默认使用的从程序集获取Type[]
internal static Type[] GetTypes(Assembly assembly)
{
return assembly.GetTypes();
} // 要以Controller结尾,但不能就是Controller,因为路由解析的控制器也不会为空
internal static bool HasValidControllerName(Type controllerType)
{
Contract.Assert(controllerType != null);
string controllerSuffix = DefaultHttpControllerSelector.ControllerSuffix;
return controllerType.Name.Length > controllerSuffix.Length && controllerType.Name.EndsWith(controllerSuffix, StringComparison.OrdinalIgnoreCase);
} //设置从程序集获取Type[]的委托
internal void SetGetTypesFunc(Func<Assembly, Type[]> getTypesFunc)
{
_getTypesFunc = getTypesFunc;
} private static bool TypeIsVisible(Type type)
{
//IsVisible是不是可以由程序集代码外访问
return (type != null && type.IsVisible);
}
}

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

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

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

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"。

  注意:

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

internal sealed class HttpControllerTypeCache
{
private readonly HttpConfiguration _configuration;
//惰性加载,缓存,Key为控制器名称出去Controller的部分(不区分大小写),
//Value为一个ILookup<string, Type>,其Key可以重复,为控制所在的命名空间,Value为对应的控制器类型
//相同名称的控制器可能存在不同程序集和不同命名空间下
private readonly Lazy<Dictionary<string, ILookup<string, Type>>> _cache; public HttpControllerTypeCache(HttpConfiguration configuration)
{
if (configuration == null)
{
throw Error.ArgumentNull("configuration");
} _configuration = configuration;
_cache = new Lazy<Dictionary<string, ILookup<string, Type>>>(InitializeCache);
} //由于使用Lazy,调用该属性时候,才调用下边的InitializeCache
internal Dictionary<string, ILookup<string, Type>> Cache
{
get { return _cache.Value; }
} //根据控制器名称获取可选的ControllerType列表,从缓存读取
public ICollection<Type> GetControllerTypes(string controllerName)
{
if (String.IsNullOrEmpty(controllerName))
{
throw Error.ArgumentNullOrEmpty("controllerName");
} HashSet<Type> matchingTypes = new HashSet<Type>(); ILookup<string, Type> namespaceLookup;
if (_cache.Value.TryGetValue(controllerName, out namespaceLookup))
{
foreach (var namespaceGroup in namespaceLookup)
{
matchingTypes.UnionWith(namespaceGroup);
}
} return matchingTypes;
} //初始化缓存
private Dictionary<string, ILookup<string, Type>> InitializeCache()
{
//获取AssembliesResolver服务实例
IAssembliesResolver assembliesResolver = _configuration.Services.GetAssembliesResolver();
//获取ControllersResolver服务实例
IHttpControllerTypeResolver controllersResolver = _configuration.Services.GetHttpControllerTypeResolver();
//调用ControllersResolver.GetControllerTypes以assembliesResolver为参数获取ControllerType列表
ICollection<Type> controllerTypes = controllersResolver.GetControllerTypes(assembliesResolver);
//先对解析出来的ControllerType列表按照ControllerType去除Controller后的名称分组,不区分大小写(OrdinalIgnoreCase)
var groupedByName = controllerTypes.GroupBy(
t => t.Name.Substring(, t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length),
StringComparer.OrdinalIgnoreCase);
//再转换成Dictionary<string, ILookup<string, Type>>缓存结构
return groupedByName.ToDictionary(
g => g.Key,
g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase),
StringComparer.OrdinalIgnoreCase);
}
}

4、IHttpControllerSelector DefaultHttpControllerSelector

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

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

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

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

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

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

  主要逻辑:

  • 控制器名称获取,不管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里读取数据时候,才去构建缓存内容,详细见代码注释
public class DefaultHttpControllerSelector : IHttpControllerSelector
{
public static readonly string ControllerSuffix = "Controller"; private const string ControllerKey = "controller"; private readonly HttpConfiguration _configuration;
//ControllerType缓存
private readonly HttpControllerTypeCache _controllerTypeCache;
private readonly Lazy<ConcurrentDictionary<string, HttpControllerDescriptor>> _controllerInfoCache; public DefaultHttpControllerSelector(HttpConfiguration configuration)
{
if (configuration == null)
{
throw Error.ArgumentNull("configuration");
}
//Lazy惰性加载,用到_controllerInfoCache时候才去执行InitializeControllerInfoCache,进行缓存数据构建
_controllerInfoCache = new Lazy<ConcurrentDictionary<string, HttpControllerDescriptor>>(InitializeControllerInfoCache);
_configuration = configuration;
_controllerTypeCache = new HttpControllerTypeCache(_configuration);
} //从请求中匹配指定控制器名称的控制器描述符号,从缓存中读取,缓存构建时机是在读取缓存时候,使用Lazy实现
public virtual HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
} IHttpRouteData routeData = request.GetRouteData();
HttpControllerDescriptor controllerDescriptor;
if (routeData != null)
{
//先按特性路由(以后再说)解析,如果解析出数据,就直接返回
controllerDescriptor = GetDirectRouteController(routeData);
if (controllerDescriptor != null)
{
return controllerDescriptor;
}
}
//非特性路由则
//从HttpRequestMessage属性字典中获取控制器名称,获取不到就NotFound
string controllerName = GetControllerName(request);
if (String.IsNullOrEmpty(controllerName))
{
throw new HttpResponseException(request.CreateErrorResponse(
HttpStatusCode.NotFound,
Error.Format(SRResources.ResourceNotFound, request.RequestUri),
Error.Format(SRResources.ControllerNameNotFound, request.RequestUri)));
}
//从控制器描述符缓存中获取,找到就直接返回,在此Lazy惰性加载,才去执行InitializeControllerInfoCache,进行缓存数据构建
if (_controllerInfoCache.Value.TryGetValue(controllerName, out controllerDescriptor))
{
return controllerDescriptor;
} //找不到就根据实际情况,抛出不同异常
ICollection<Type> matchingTypes = _controllerTypeCache.GetControllerTypes(controllerName); // ControllerInfoCache is already initialized.
Contract.Assert(matchingTypes.Count != );
//根据不同原因创建不同类型异常
if (matchingTypes.Count == )
{
// 没有匹配
throw new HttpResponseException(request.CreateErrorResponse(
HttpStatusCode.NotFound,
Error.Format(SRResources.ResourceNotFound, request.RequestUri),
Error.Format(SRResources.DefaultControllerFactory_ControllerNameNotFound, controllerName)));
}
else
{
// 匹配多个类型
throw CreateAmbiguousControllerException(request.GetRouteData().Route, controllerName, matchingTypes);
}
} public virtual IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
{
return _controllerInfoCache.Value.ToDictionary(c => c.Key, c => c.Value, StringComparer.OrdinalIgnoreCase);
} //从HttpRequestMessage的属性字典中获取控制器名称
public virtual string GetControllerName(HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}
//先从HttpRequestMessage的属性字典中获取路由数据
IHttpRouteData routeData = request.GetRouteData();
if (routeData == null)
{
return null;
} // TryGetValue获取key为controller的路由变量值
string controllerName = null;
routeData.Values.TryGetValue(ControllerKey, out controllerName);
return controllerName;
} //特性路由逻辑以后再说
private static HttpControllerDescriptor GetDirectRouteController(IHttpRouteData routeData)
{
CandidateAction[] candidates = routeData.GetDirectRouteCandidates();
if (candidates != null)
{
// Set the controller descriptor for the first action descriptor
Contract.Assert(candidates.Length > );
Contract.Assert(candidates[].ActionDescriptor != null); HttpControllerDescriptor controllerDescriptor = candidates[].ActionDescriptor.ControllerDescriptor; // Check that all other candidate action descriptors share the same controller descriptor
for (int i = ; i < candidates.Length; i++)
{
CandidateAction candidate = candidates[i];
if (candidate.ActionDescriptor.ControllerDescriptor != controllerDescriptor)
{
// We've found an ambiguity (multiple controllers matched)
throw CreateDirectRouteAmbiguousControllerException(candidates);
}
} return controllerDescriptor;
} return null;
} private static Exception CreateDirectRouteAmbiguousControllerException(CandidateAction[] candidates)
{
Contract.Assert(candidates != null);
Contract.Assert(candidates.Length > ); HashSet<Type> matchingTypes = new HashSet<Type>();
for (int i = ; i < candidates.Length; i++)
{
matchingTypes.Add(candidates[i].ActionDescriptor.ControllerDescriptor.ControllerType);
} // we need to generate an exception containing all the controller types
StringBuilder typeList = new StringBuilder();
foreach (Type matchedType in matchingTypes)
{
typeList.AppendLine();
typeList.Append(matchedType.FullName);
} return Error.InvalidOperation(SRResources.DirectRoute_AmbiguousController, typeList, Environment.NewLine);
} private static Exception CreateAmbiguousControllerException(IHttpRoute route, string controllerName, ICollection<Type> matchingTypes)
{
Contract.Assert(route != null);
Contract.Assert(controllerName != null);
Contract.Assert(matchingTypes != null); // Generate an exception containing all the controller types
StringBuilder typeList = new StringBuilder();
foreach (Type matchedType in matchingTypes)
{
typeList.AppendLine();
typeList.Append(matchedType.FullName);
} string errorMessage = Error.Format(SRResources.DefaultControllerFactory_ControllerNameAmbiguous_WithRouteTemplate, controllerName, route.RouteTemplate, typeList, Environment.NewLine);
return new InvalidOperationException(errorMessage);
} //初始化构建ConcurrentDictionary<string, HttpControllerDescriptor>缓存,根据Dictionary<string, ILookup<string, Type>>类型 列表缓存
private ConcurrentDictionary<string, HttpControllerDescriptor> InitializeControllerInfoCache()
{
var result = new ConcurrentDictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase);
//由于同一控制器名称在不同命名空间中存在多个控制器类型,所以要去掉重复的,用来记录重复的Key
var duplicateControllers = new HashSet<string>();
//先从控制器类型列表中缓存中获取控制器类型列表
Dictionary<string, ILookup<string, Type>> controllerTypeGroups = _controllerTypeCache.Cache; //遍历
foreach (KeyValuePair<string, ILookup<string, Type>> controllerTypeGroup in controllerTypeGroups)
{
string controllerName = controllerTypeGroup.Key; foreach (IGrouping<string, Type> controllerTypesGroupedByNs in controllerTypeGroup.Value)
{
foreach (Type controllerType in controllerTypesGroupedByNs)
{
if (result.Keys.Contains(controllerName))
{
//有重复就记录在重复集合里,待移除处理
duplicateControllers.Add(controllerName);
break;
}
else
{
//new HttpControllerDescriptor
result.TryAdd(controllerName, new HttpControllerDescriptor(_configuration, controllerName, controllerType));
}
}
}
}
//去掉有重复的匹配控制器的数据
foreach (string duplicateController in duplicateControllers)
{
HttpControllerDescriptor descriptor;
result.TryRemove(duplicateController, out descriptor);
} return result;
}
}

 5、IHttpControllerActivator DefaultHttpControllerActivator

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

  public interface IHttpControllerActivator
{
//根据HttpControllerDescriptor创建出IHttpController
IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType);
}

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

  主要逻辑:

  • 在Create方法中,如果dependency resolver可以解析返回,就直接返回,否则就用创建委托activator来执行创建,而创建委托activator可以缓存到本地缓存和controllerDescriptor.Properties cache缓存,由上一篇可以知道,默认的IoC容器是EmptyResolver,所以dependency resolver都是返回空,所以每次都是通过反射创建实例。
  • activator通过反射来创建,在第一点中缓存的是创建对象的委托,而不是HttpController实例,其每次都是重新创建,所以对于多个针对相同的HttpControlIer类型的请求来说,最终创建的HttpController实例都是不同的
 public class DefaultHttpControllerActivator : IHttpControllerActivator
{
//缓存HttpControllerDescriptor对应的创建委托
private Tuple<HttpControllerDescriptor, Func<IHttpController>> _fastCache;
private object _cacheKey = new object(); //核心创建方法,如果dependency resolver可以解析返回,就直接返回,否则就用创建委托activator来执行创建,
//而创建委托activator可以缓存到本地缓存和controllerDescriptor.Properties cache缓存
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
if (request == null)
{
throw Error.ArgumentNull("request");
} if (controllerDescriptor == null)
{
throw Error.ArgumentNull("controllerDescriptor");
} if (controllerType == null)
{
throw Error.ArgumentNull("controllerType");
} try
{
Func<IHttpController> activator; //如果没有定义本地快速缓存
if (_fastCache == null)
{
IHttpController controller = GetInstanceOrActivator(request, controllerType, out activator);
if (controller != null)
{
//这里返回的是dependency resolver中有定义时候,定义的Controller实例
return controller;
}
else
{
//初始化创建一个本地缓存cacheItem
Tuple<HttpControllerDescriptor, Func<IHttpController>> cacheItem = Tuple.Create(controllerDescriptor, activator);
Interlocked.CompareExchange(ref _fastCache, cacheItem, null);
}
}
else if (_fastCache.Item1 == controllerDescriptor)
{
// 如果有定义本地快速缓存,而且匹配controllerDescriptor key就直接返回
activator = _fastCache.Item2;
}
else
{
// 如果有定义本地快速缓存,没有匹配controllerDescriptor key,就从controllerDescriptor.Properties cache中获取创建委托
object value;
if (controllerDescriptor.Properties.TryGetValue(_cacheKey, out value))
{
activator = (Func<IHttpController>)value;
}
else
{
IHttpController controller = GetInstanceOrActivator(request, controllerType, out activator);
if (controller != null)
{
//这里返回的是dependency resolver中有定义时候,定义的Controller实例
return controller;
}
else
{
//添加进HttpControllerDescriptor.Properties cache
controllerDescriptor.Properties.TryAdd(_cacheKey, activator);
}
}
}
//执行创建委托,创建实例
return activator();
}
catch (Exception ex)
{
throw Error.InvalidOperation(ex, SRResources.DefaultControllerFactory_ErrorCreatingController, controllerType.Name);
}
} // 返回控制器实例如果在dependency resolver得到就直接返回,否则通过反射创建
private static IHttpController GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, out Func<IHttpController> activator)
{
Contract.Assert(request != null);
Contract.Assert(controllerType != null); // 如果dependency resolver可以直接返回controller就直接返回使用
IHttpController instance = (IHttpController)request.GetDependencyScope().GetService(controllerType);
if (instance != null)
{
activator = null;
return instance;
} //如果dependency resolver没有定义,就返回通过反射直接创建的委托
activator = TypeActivator.Create<IHttpController>(controllerType);
return null;
}
}

 二、自定义扩展组件HttpControllerActivator

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

   public class UnityHttpControllerActivator : IHttpControllerActivator
{
public IUnityContainer UnityContainer { get; private set; } public UnityHttpControllerActivator(IUnityContainer unityContainer)
{
this.UnityContainer = unityContainer;
} public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
return (IHttpController)this.UnityContainer.Resolve(controllerType);
}
}

  注册:

 UnityContainer unityContainer = new UnityContainer();
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator),new UnityHttpControllerActivator(unityContainer));
上一篇:Android 工具视频学习笔记_WDS


下一篇:创建支持复杂脚本Complex Scripts的WINCE6.0系统