Inside ASP.NET MVC: IDependencyResolver - Service locator in MVC
All types inside ASP.NET MVC3 framework are being resolved by IDependencyResolver
. The design goal of this interface is to provide flexibility and decrease coupling between components.
namespace System.Web.Mvc {
using System.Collections.Generic;
public interface IDependencyResolver {
object GetService(Type serviceType);
IEnumerable<object> GetServices(Type serviceType);
}
}
If take a look into the code you will definitely smell the Service Locator pattern. Indeed, IDependencyResolver
is pure service locator.
DependencyResolver as IDependencyResolver holder
IDependencyResolver
instance is being accessed through the DependencyResolver
class.
public class DependencyResolver {
// Static accessors
private static DependencyResolver _instance = new DependencyResolver();
public static IDependencyResolver Current {
get {
return _instance.InnerCurrent;
}
}
It is a singleton class, current instance is being accessed through Current
property. The default implementation is DefaultDependencyResolver
.
// Instance implementation (for testing purposes)
private IDependencyResolver _current = new DefaultDependencyResolver();
Even if the comment says (for testing purposes) that class is used in real code. Let’s take a look on that.
private class DefaultDependencyResolver : IDependencyResolver {
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This method might throw exceptions whose type we cannot strongly link against; namely, ActivationException from common service locator")]
public object GetService(Type serviceType) {
try {
return Activator.CreateInstance(serviceType);
}
catch {
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType) {
return Enumerable.Empty<object>();
}
}
As you might see, it is extremely simple. It just tries to resolve the type by Activator
class. If the type could be resolved it just returns it’s instance, otherwise just return null. The GetServices
method just returns empty enumerable.
Substituting default DependencyResolver
As I said above, the main design goal of DependencyResolver
is to provide flexibility. By flexibility I mean just easy way to substitute any type with own implementation. Say you want to change the ControllerFactory
or ModelBinder
or what ever you like. Everything is possible just by overriding IDependencyResolver
.
I’ve seen one common misconception about MVC3, that it is contains IoC container inside it. It is not true, but it expose the interface which really much suites interfaces of famous IoC containers. To do not have a strict rules and force developers to use one type of IoC, ASP.NET MVC developers created a facility by which you can integrate yours IoC of choice. Let’s have a look how to do that.
DependencyResolver
contains the number of setters to substitute the instance.
public static void SetResolver(IDependencyResolver resolver) {
_instance.InnerSetResolver(resolver);
}
public static void SetResolver(object commonServiceLocator) {
_instance.InnerSetResolver(commonServiceLocator);
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types.")]
public static void SetResolver(Func<Type, object> getService, Func<Type, IEnumerable<object>> getServices) {
_instance.InnerSetResolver(getService, getServices);
}
As example of implementation here my very dummy dependency resolver.
namespace MvcForDebug2.Infrastructure {
public class DummyDependencyResolver : IDependencyResolver {
public object GetService(Type serviceType) {
if (serviceType.Equals(typeof(IControllerFactory))) {
return new DummyControllerFactory();
}
return null;
}
public IEnumerable<object> GetServices(Type serviceType) {
return null;
}
}
}
Finally, in global.asx.cs you need to set it up.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
DependencyResolver.SetResolver(new DummyDependencyResolver());
//ControllerBuilder.Current.SetControllerFactory(new DummyControllerFactory());
}
Conclusions
IDependencyResolver
is a powerful feature of ASP.NET MVC3. It is used to create all internal MVC types, so by overriding it you can override default behavior of many framework aspects. Typically you should not have any complex code in GetService
and GetServices
methods, but instead just delegation of call to IoC container.
All types inside ASP.NET MVC3 framework are being resolved by IDependencyResolver
. The design goal of this interface is to provide flexibility and decrease coupling between components.
namespace System.Web.Mvc { using System.Collections.Generic; public interface IDependencyResolver { object GetService(Type serviceType); IEnumerable<object> GetServices(Type serviceType); } }
If take a look into the code you will definitely smell the Service Locator pattern. Indeed, IDependencyResolver
is pure service locator.
DependencyResolver as IDependencyResolver holder
IDependencyResolver
instance is being accessed through the DependencyResolver
class.
public class DependencyResolver { // Static accessors private static DependencyResolver _instance = new DependencyResolver(); public static IDependencyResolver Current { get { return _instance.InnerCurrent; } }
It is a singleton class, current instance is being accessed through Current
property. The default implementation is DefaultDependencyResolver
.
// Instance implementation (for testing purposes) private IDependencyResolver _current = new DefaultDependencyResolver();
Even if the comment says (for testing purposes) that class is used in real code. Let’s take a look on that.
private class DefaultDependencyResolver : IDependencyResolver { [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This method might throw exceptions whose type we cannot strongly link against; namely, ActivationException from common service locator")] public object GetService(Type serviceType) { try { return Activator.CreateInstance(serviceType); } catch { return null; } } public IEnumerable<object> GetServices(Type serviceType) { return Enumerable.Empty<object>(); } }
As you might see, it is extremely simple. It just tries to resolve the type by Activator
class. If the type could be resolved it just returns it’s instance, otherwise just return null. The GetServices
method just returns empty enumerable.
Substituting default DependencyResolver
As I said above, the main design goal of DependencyResolver
is to provide flexibility. By flexibility I mean just easy way to substitute any type with own implementation. Say you want to change the ControllerFactory
or ModelBinder
or what ever you like. Everything is possible just by overriding IDependencyResolver
.
I’ve seen one common misconception about MVC3, that it is contains IoC container inside it. It is not true, but it expose the interface which really much suites interfaces of famous IoC containers. To do not have a strict rules and force developers to use one type of IoC, ASP.NET MVC developers created a facility by which you can integrate yours IoC of choice. Let’s have a look how to do that.
DependencyResolver
contains the number of setters to substitute the instance.
public static void SetResolver(IDependencyResolver resolver) { _instance.InnerSetResolver(resolver); } public static void SetResolver(object commonServiceLocator) { _instance.InnerSetResolver(commonServiceLocator); } [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types.")] public static void SetResolver(Func<Type, object> getService, Func<Type, IEnumerable<object>> getServices) { _instance.InnerSetResolver(getService, getServices); }
As example of implementation here my very dummy dependency resolver.
namespace MvcForDebug2.Infrastructure { public class DummyDependencyResolver : IDependencyResolver { public object GetService(Type serviceType) { if (serviceType.Equals(typeof(IControllerFactory))) { return new DummyControllerFactory(); } return null; } public IEnumerable<object> GetServices(Type serviceType) { return null; } } }
Finally, in global.asx.cs you need to set it up.
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); DependencyResolver.SetResolver(new DummyDependencyResolver()); //ControllerBuilder.Current.SetControllerFactory(new DummyControllerFactory()); }
Conclusions
IDependencyResolver
is a powerful feature of ASP.NET MVC3. It is used to create all internal MVC types, so by overriding it you can override default behavior of many framework aspects. Typically you should not have any complex code in GetService
and GetServices
methods, but instead just delegation of call to IoC container.