• Asp.net MVC源码分析DependencyResolver与Service Location


    这一篇我们讲解如何利用DependencyResolver来定位我们的自定义服务(service)也就查找Controller.

    首先让我们来看一下DependencyResolver 的实现。

    DependencyResolver.cs

    View Code
     1  public class DependencyResolver {
    2 // Static accessors
    3
    4 private static DependencyResolver _instance = new DependencyResolver();
    5
    6 public static IDependencyResolver Current {
    7 get {
    8 return _instance.InnerCurrent;
    9 }
    10 }
    11
    12 public static void SetResolver(IDependencyResolver resolver) {
    13 _instance.InnerSetResolver(resolver);
    14 }
    15
    16 public static void SetResolver(object commonServiceLocator) {
    17 _instance.InnerSetResolver(commonServiceLocator);
    18 }
    19
    20 [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types.")]
    21 public static void SetResolver(Func<Type, object> getService, Func<Type, IEnumerable<object>> getServices) {
    22 _instance.InnerSetResolver(getService, getServices);
    23 }
    24
    25 // Instance implementation (for testing purposes)
    26
    27 private IDependencyResolver _current = new DefaultDependencyResolver();
    28
    29 public IDependencyResolver InnerCurrent {
    30 get {
    31 return _current;
    32 }
    33 }
    34
    35 private class DefaultDependencyResolver : IDependencyResolver {
    36 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This method might throw exceptions whose type we cannot strongly link against; namely, ActivationException from common service locator")]
    37 public object GetService(Type serviceType) {
    38 try {
    39 return Activator.CreateInstance(serviceType);
    40 }
    41 catch {
    42 return null;
    43 }
    44 }
    45
    46 public IEnumerable<object> GetServices(Type serviceType) {
    47 return Enumerable.Empty<object>();
    48 }
    49 }
    50 }
    51
    52

    DependencyResolver.Current 默认返回的是 DefaultDependencyResolver 类型的实例,在这个类中我们看到它实现了IDependencyResolver.GetService 接口, 这个实现是调用了Activator.CreateInstance(serviceType); 返回一个类型的实例。

    这里框架为我们提供了一个时点使我们可以调用DependencyResolver.SetResolver方法来注入我们自己的IDependencyResolver的实现

    ---------------------------------------------------------------------------------------------

    接下来我们看MvcHandler,所有的Request请需要在这里查找我们的Controller,在这个类的ProcessRequestInit方法中我们可以看到它调用了 ControllerBuilder.GetControllerFactory(); 先找到Controller的工成类实例IControllerFactory,再调用它的CreateController方法来寻找和创建Controller.

    MvcHandler.cs

    View Code
     1   private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory) {
    2 // If request validation has already been enabled, make it lazy. This allows attributes like [HttpPost] (which looks
    3 // at Request.Form) to work correctly without triggering full validation.
    4 bool? isRequestValidationEnabled = ValidationUtility.IsValidationEnabled(HttpContext.Current);
    5 if (isRequestValidationEnabled == true) {
    6 ValidationUtility.EnableDynamicValidation(HttpContext.Current);
    7 }
    8
    9 AddVersionHeader(httpContext);
    10 RemoveOptionalRoutingParameters();
    11
    12 // Get the controller type
    13 string controllerName = RequestContext.RouteData.GetRequiredString("controller");
    14
    15 // Instantiate the controller and call Execute
    16 factory = ControllerBuilder.GetControllerFactory();
    17 controller = factory.CreateController(RequestContext, controllerName);
    18 if (controller == null) {
    19 throw new InvalidOperationException(
    20 String.Format(
    21 CultureInfo.CurrentCulture,
    22 MvcResources.ControllerBuilder_FactoryReturnedNull,
    23 factory.GetType(),
    24 controllerName));
    25 }
    26 }

    -------------------------------------------------------------------------------------------

    下面我们看一下ControllerBuilder类,看一下它是如何工作的。

    ControllerBuilder.cs

    View Code
     1   public class ControllerBuilder {
    2
    3 private Func<IControllerFactory> _factoryThunk = () => null;
    4 private static ControllerBuilder _instance = new ControllerBuilder();
    5 private HashSet<string> _namespaces = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
    6 private IResolver<IControllerFactory> _serviceResolver;
    7
    8 public ControllerBuilder()
    9 : this(null) {
    10 }
    11
    12 internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver) {
    13 _serviceResolver = serviceResolver ?? new SingleServiceResolver<IControllerFactory>(
    14 () => _factoryThunk(),
    15 new DefaultControllerFactory { ControllerBuilder = this },
    16 "ControllerBuilder.GetControllerFactory"
    17 );
    18 }
    19
    20 public IControllerFactory GetControllerFactory() {
    21 return _serviceResolver.Current;
    22 }
    23 }

    在构造函数中我们看到它初始化了_serviceResolver 变量,它的类型是SingleServiceResolver<IControllerFactory>,在它初始化时传入了_factoryThunk(返回值为空的委托),和DefaultControllerFactory实例。接下来我们看一下SingleServiceResolver的实现。

    SingleServiceResolver.cs

    View Code
     1   internal class SingleServiceResolver<TService> : IResolver<TService> where TService : class {
    2
    3 private TService _currentValueFromResolver;
    4 private Func<TService> _currentValueThunk;
    5 private TService _defaultValue;
    6 private Func<IDependencyResolver> _resolverThunk;
    7 private string _callerMethodName;
    8
    9 public SingleServiceResolver(Func<TService> currentValueThunk, TService defaultValue, string callerMethodName) {
    10 if (currentValueThunk == null) {
    11 throw new ArgumentNullException("currentValueThunk");
    12 }
    13 if (defaultValue == null) {
    14 throw new ArgumentNullException("defaultValue");
    15 }
    16
    17 _resolverThunk = () => DependencyResolver.Current;
    18 _currentValueThunk = currentValueThunk;
    19 _defaultValue = defaultValue;
    20 _callerMethodName = callerMethodName;
    21 }
    22
    23 internal SingleServiceResolver(Func<TService> staticAccessor, TService defaultValue, IDependencyResolver resolver, string callerMethodName)
    24 : this(staticAccessor, defaultValue, callerMethodName) {
    25 if (resolver != null) {
    26 _resolverThunk = () => resolver;
    27 }
    28 }
    29
    30 public TService Current {
    31 get {
    32 if (_resolverThunk != null) {
    33 lock (_currentValueThunk) {
    34 if (_resolverThunk != null) {
    35 _currentValueFromResolver = _resolverThunk().GetService<TService>();
    36 _resolverThunk = null;
    37
    38 if (_currentValueFromResolver != null && _currentValueThunk() != null) {
    39 throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, MvcResources.SingleServiceResolver_CannotRegisterTwoInstances, typeof(TService).Name.ToString(), _callerMethodName));
    40 }
    41 }
    42 }
    43 }
    44 return _currentValueFromResolver ?? _currentValueThunk() ?? _defaultValue;
    45 }
    46 }
    47 }

    我们看到 

    _resolverThunk = () => DependencyResolver.Current;//这里就为我们注入自己的ControllerFactory提供机会_currentValueFromResolver = _resolverThunk().GetService<TService>();我们知道框架使用了DependencyResolver.Current来提供GetService的功能,如果没有则返回默认的DefaultControllerFactory实例(从构造函数中传入)。

    --------------------------------------------------------------------------------------------

    接下来我们看DefaultControllerFactory的实现,

    View Code
     1     public class DefaultControllerFactory : IControllerFactory {
    2 public DefaultControllerFactory()
    3 : this(null, null, null) {
    4 }
    5
    6 public DefaultControllerFactory(IControllerActivator controllerActivator)
    7 : this(controllerActivator, null, null) {
    8 }
    9
    10 internal DefaultControllerFactory(IControllerActivator controllerActivator, IResolver<IControllerActivator> activatorResolver, IDependencyResolver dependencyResolver) {
    11 if (controllerActivator != null) {
    12 _controllerActivator = controllerActivator;
    13 }
    14 else {
    15 _activatorResolver = activatorResolver ?? new SingleServiceResolver<IControllerActivator>(
    16 () => null,
    17 new DefaultControllerActivator(dependencyResolver),
    18 "DefaultControllerFactory contstructor"
    19 );
    20 }
    21 }
    22
    23 private IControllerActivator ControllerActivator {
    24 get {
    25 if (_controllerActivator != null) {
    26 return _controllerActivator;
    27 }
    28 _controllerActivator = _activatorResolver.Current;
    29 return _controllerActivator;
    30 }
    31 }
    32
    33 public virtual IController CreateController(RequestContext requestContext, string controllerName) {
    34 if (requestContext == null) {
    35 throw new ArgumentNullException("requestContext");
    36 }
    37 if (String.IsNullOrEmpty(controllerName)) {
    38 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
    39 }
    40 Type controllerType = GetControllerType(requestContext, controllerName);
    41 IController controller = GetControllerInstance(requestContext, controllerType);
    42 return controller;
    43 }
    44
    45 protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType) {
    46
    47 return ControllerActivator.Create(requestContext, controllerType);
    48 }
    49
    50
    51
    52 private class DefaultControllerActivator : IControllerActivator {
    53 Func<IDependencyResolver> _resolverThunk;
    54
    55 public DefaultControllerActivator()
    56 : this(null) {
    57 }
    58
    59 public DefaultControllerActivator(IDependencyResolver resolver) {
    60 if (resolver == null) {
    61 _resolverThunk = () => DependencyResolver.Current;
    62 }
    63 else {
    64 _resolverThunk = () => resolver;
    65 }
    66 }
    67
    68 public IController Create(RequestContext requestContext, Type controllerType) {
    69 try {
    70 return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
    71 }
    72 catch (Exception ex) {
    73 throw new InvalidOperationException(
    74 String.Format(
    75 CultureInfo.CurrentCulture,
    76 MvcResources.DefaultControllerFactory_ErrorCreatingController,
    77 controllerType),
    78 ex);
    79 }
    80 }
    81 }
    82 }
    83 }

    在这个类中我们同样看到了和ControllerBuilder中一样的模式,也是利用SingleServiceResolver,来初始化IControllerActivator实例。如果在DependencyResolver.Current中没有找到IControllerActivator类型的话使用DefaultControllerActivator.最终利用DefaultControllerActivator.Create方法创建Controller的实例。

    这里框架又提供了一个时点让我们注册自已实现的IControllerActivator类。 

    总结:

    DependencyResolver 与 SingleServiceResolver/MutiServiceResolver 在MVC框架中配合使用的。

    只要用到了ServiceResolver的地方,我们都可能通过在DependencyResolver 注册自己的行为从而改变框架的行为。

    口渴中。。 

    不知道说清楚没,下一篇我们分析Ninject.MVC 与 asp.net MVC 的集成。

    转载请注明出处:http://www.cnblogs.com/RobbinHan/archive/2011/12/05/2270707.html 

    本文作者: 十一月的雨 http://www.cnblogs.com/RobbinHan

  • 相关阅读:
    第九周周记
    第七周周记
    第三次作业第一题
    第五周周记
    《世界是数字的》读后感想
    第十周周记
    迷茫
    测试作业
    价值观作业
    作业二 感想
  • 原文地址:https://www.cnblogs.com/RobbinHan/p/2269537.html
Copyright © 2020-2023  润新知