Alexander Beletsky's development blog

My profession is engineering

Inside ASP.NET MVC: IResolver and it's implementations

One of the major changes between MVC2 and MVC3 was introduction of Dependency Injection principles on a level of framework. If you compare, for instance ControllerBuilder.cs from MVC2 and ControllerBuilder.cs from MVC3 you will clearly see the difference. In MVC3 we are no longer create entities directly (through ‘new’ operator), but instead we delegate that to IResolver interface. IResolver interface itself is extremely simple:

namespace System.Web.Mvc {
    internal interface IResolver<T> {
        T Current { get; }
    }
}

We can just ask the instance of type we would like to resolve. Please also note, that IResolver is internal class, so it is not exposed and you will never use it in application directly.

All major entities of MVC framework (ControllerFactory, Filters, ViewEngines etc.) from now resolved by IResolver implementation class. That improves extensibility of framework very much and introduces new strategy of creation objects.

Implementations of IResolver interface

There are two classes that implements IResolver - SingleServiceResolver and MultiServiceResolver. Primary responsibility of those are delegation call to IDependencyResolver methods GetService and GetServices, respectively.

If they just recalling method of IDependecyResolver class, what’s are the purpose of those two classes?

There are 2 purposes I can see:

  1. To provide default type instance in case of type is not resolved by IDependencyResolver.
  2. To create instance only once.

How it works?

Now, let’s take a look how it actually works. It is really simple and small, so I’m able to put most of code here.

Construction:

public SingleServiceResolver(Func<TService> currentValueThunk, TService defaultValue, string callerMethodName) {
 if (currentValueThunk == null) {
  throw new ArgumentNullException("currentValueThunk");
 }
 if (defaultValue == null) {
  throw new ArgumentNullException("defaultValue");
 }

 _resolverThunk = () => DependencyResolver.Current;
 _currentValueThunk = currentValueThunk;
 _defaultValue = defaultValue;
 _callerMethodName = callerMethodName;
}

You can see, it receives default factory method, default type instance and the name of caller method (used as additional information in exception).

Here, how ControllerBuilder creates the SingleServiceResolver, for instance:

internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver) {
 _serviceResolver = serviceResolver ?? new SingleServiceResolver<IControllerFactory>(
  () => _factoryThunk(),
   new DefaultControllerFactory { ControllerBuilder = this },
  "ControllerBuilder.GetControllerFactory"
 );
}

Since it implements only one property, current Current:

public TService Current {
 get {
  if (_resolverThunk != null) {
   lock (_currentValueThunk) {
    if (_resolverThunk != null) {
     _currentValueFromResolver = _resolverThunk().GetService<TService>();
     _resolverThunk = null;

     if (_currentValueFromResolver != null && _currentValueThunk() != null) {
      throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, MvcResources.SingleServiceResolver_CannotRegisterTwoInstances, typeof(TService).Name.ToString(), _callerMethodName));
     }
    }
   }
  }
  return _currentValueFromResolver ?? _currentValueThunk() ?? _defaultValue;
 }
}

First, we check the existence of _resolverThunk it would always exist (having value of () => DependencyResolver.Current) for first call of the method. Then, we locking on _currentValueThunk protecting for multiple threads access the same method, same time. Then, we try to resolve given type by asking _resolverThunk() to GetService<TService>().

After that we have an if-statement that I didn’t get from the very beginning. Fortunately, MVC project has bunch of good unit tests. As I found the test it turns clear to me. The test called CurrentThrowsIfCurrentSetThroughServiceAndSetter and it’s Assert part:

[TestMethod]
public void CurrentThrowsIfCurrentSetThroughServiceAndSetter() {
 // Arrange
 TestProvider providerFromCurrentValueThunk = new TestProvider();
 TestProvider providerFromServiceLocation = new TestProvider();
 TestProvider providerFromDefaultValue = new TestProvider();
 Mock<IDependencyResolver> resolver = new Mock<IDependencyResolver>();

 resolver.Setup(r => r.GetService(typeof(TestProvider)))
   .Returns(providerFromServiceLocation);

 SingleServiceResolver<TestProvider> singleResolver = new SingleServiceResolver<TestProvider>(() => providerFromCurrentValueThunk, providerFromDefaultValue, resolver.Object, "TestProvider.Current");

 //Act & assert
 ExceptionHelper.ExpectException<InvalidOperationException>(
  () => singleResolver.Current,
  "An instance of TestProvider was found in the resolver as well as a custom registered provider in TestProvider.Current. Please set only one or the other."
 );
}

This is really important and says: you should not create same type instance both with IDependencyResolver and factory method! In case of ControllerFactory: you should never provide your implementation of IControllerFactory and in the same time resolve IControllerFactory instance by IDependencyResolver. Same rule for all other types. You should decide how you would like to override default behavior. In MVC3 usage of IDependencyResolver is a preferable.

The code below is wrong:

DependencyResolver.SetResolver(new DummyDependencyResolver());
ControllerBuilder.Current.SetControllerFactory(new DummyControllerFactory());

So, after that _resolverThunk is reset and we no longer ask IDependencyResolver, just returning the resolved value.

MultiServiceResolver is even a little simpler.

public IEnumerable<TService> Current {
 get {
  if (_itemsFromService == null) {
   lock (_itemsThunk) {
    if (_itemsFromService == null) {
     _itemsFromService = _resolverThunk().GetServices<TService>();
    }
   }
  }
  return _itemsFromService.Concat(_itemsThunk());
 }
}

The same, singleton strategy of resolving types and then just concatenating resolved by IDependencyResolver with ones retuned by default factory method. It looks strange, but it is legal here to have types resolved both by IDependencyResolver and factory.

Conclusions

IResolver, SingleServiceResolver and MultiServiceResolver are all internal parts of framework. We are not directly using any of them. They used as kind of bridge between previous (MVC2) object creation strategy and new (MVC3) one. New strategy is using Service Locator (IDependencyResolver). It is important that we should never ‘mix’ both in the same application. Preferable way is IDependencyResolver.

What’s next?

We are going to continues our journey of resolving types and meet IDependencyResolver closer.

Previous Inside ASP.NET MVC: ControllerBuilder class