asp.net-mvc-4dependency-injectionninjectmodelbindersdependency-resolver

When does one want to use a IDependencyResolver over a IModelBinder?


Upon the creation of a new item, when posting information from a form back to the controller, it says that no parameter-less constructor could be found. That is expected since the view model used as the model of the view depends on a domain model object.

I then decided to write my own model binder.

NewItemViewModelBinder

public class NewItemViewModelBinder : DefaultModelBinder {
    public NewItemViewModelBinder(IKernel kernel) {
        if (kernel == null) throw new ArgumentNullException("kernel");
        this.kernel = kernel;
    }

    protected override object CreateModel(ControllerContext controllerContext
        , ModelBindingContext bindingContext, Type modelType) {
        return kernel.Get(modelType);
    }

    private readonly IKernel kernel;
}

This solution with the model binder worked just fine having having registered this binder to the ModelBinders.Binders within the NinjectWebCommon.RegisterServices method.

public void RegisterServices(IKernel kernel) {
    CompositionRoot.ComposeObjectGraph();
    ModelBinders
        .Binders
        .Add(typeof(NewItemViewModel), new NewItemViewModelBinder(kernel));
}

Besides, I also came across some other posts that were talking about the DependencyResolver. So I thought that if I can write a dependency resolver that would solve all other creation problems, then I'd be out of trouble for the rest.

NinjectDependencyResolver

public class NinjectDependencyResolver : NinjectDependencyScope
    : System.Web.Http.Dependencies.IDependencyResolver
    , System.Web.Mvc.IDependencyResolver {
    public NinjectDepencyResolver(IKernel kernel
        , IDependencyScopeFactory factory) : base(kernel) {
        if (kernel == null) throw new ArgumentNullException("kernel");
        if (factory == null) throw new ArgumentNullException("factory");
        this.kernel = kernel;
    }

    public IDependencyScope BeginScope() { 
        return factory.Create(kernel.BeginBlock()); 
    }

    public object GetService(Type serviceType) {
        return kernel.TryGet(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType) {
        return kernel.GetAll(serviceType);
    }

    public void Dispose() { base.Dispose(); }

    private readonly IKernel kernel;
    private readonly IDependencyScopeFactory factory;
}

And after setting this new resolver as the dependency resolver for MVC,

DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));

it didn't work, and I had the same problem as the parameter-less constructor.

So, I have three questions.

  1. What did I do wrong with the DependencyResolver approach?
  2. What are the benefits of working with the DependencyResolver versus the ModelBinder?
  3. When to use either one?

Solution

  • According to Wrox Professional ASP.NET MVC 4, page 308, you should not use IDependencyResolver for your application.

    SHOULD YOU CONSUME DEPENDENCYRESOLVER IN YOUR APPLICATION? You might be tempted to consume IDependencyResolver from within your own application. Resist that temptation. The dependency resolver interface is exactly what MVC needs — and nothing more. It’s not intended to hide or replace the traditional API of your dependency injection container. Most containers have complex and interesting APIs; in fact, it’s likely that you will choose your container based on the APIs and features that it offers more than any other reason.

    IDependencyResolver is designed to supply dependencies to the MVC framework, not to your application.

    The way IDependencyResolver is implemented follows the service locator (anti-)pattern.

    Furthermore, IDependencyResolver is not required to use DI with MVC. A better alternative is to use IControllerFactory to inject dependencies into the controllers and using other extension points (such as IModelBinder), using constructor injection, rather than service-location.

    As for using IModelBinder, you are using a good practice with your example, because you are doing constructor injection (although some might argue that models shouldn't have dependencies, but that depends on your framework design).

    As developers we always tend to try to generalize designs as much as possible, after all, that is usually the best course of action. However, when it comes to DI we have to fight that urge. For DI it is better to have each class explicitly ask for its own dependencies by type so it is obvious what a class requires to function. Service locator is at the opposite end of this spectrum - it is a black box of services that may or may not contain all of the types necessary for the application to run and it makes an application more difficult to configure.