1

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?
NightOwl888
  • 55,572
  • 24
  • 139
  • 212
Will Marcouiller
  • 23,773
  • 22
  • 96
  • 162
  • Just add a paramerless constructor in you view model (the error is thrown because internally the `DefaultModelBinder` uses `Activator.CreateInstance` to initialize an instance of your view model but it can't unless it has a paramerless constructor. –  Feb 08 '15 at 21:27
  • Yes, I know that, and already did this at first to patch. Besides, I hate to patch my code, so this is the reason of the question whilst using constructor injection is best when applying DI adequately. If I were to use a default constructor, I would have to make it pass a new instance of the model. As a result, I would be tight-coupling the code, which is exactly what is to be avoided. – Will Marcouiller Feb 08 '15 at 21:45
  • If you have a parameterless constructor (in addition to your existing constructors) you don't have to _make it pass a new instance of the model_ The `DefaultModelBinder` will initialize it and bind your values –  Feb 08 '15 at 21:55

1 Answers1

2

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.

NightOwl888
  • 55,572
  • 24
  • 139
  • 212
  • I didn't know that the IDependencyResolver used the Service Locator anti-pattern. Thanks for this information, as well as reassuring me as for the use of the IModelBinder. I use constructor injection in my model because the ViewModel interacts with the model itself, so for a ViewModel to exist, I believe it makes sense to make it dependent of my model, which model can consists of anything the application has to display to the user. Where I doubt, is that the kernel/container should only be used within the composition root, and I wonder whether it is good to pass it into the model binder. – Will Marcouiller Feb 09 '15 at 15:05
  • 1
    Using the kernel/container that way is (almost) exactly the same as implementing it within IControllerFactory. You are essentially using IModelBinder as an abstract factory to create your model. As long as you understand that the IControllerFactory and IModelBinder are part of the composition root, and that you shouldn't be liberally injecting the container all over your application, you are fine. I find it helpful to make a facade abstraction around the container object, both to decouple the application from the container and to help ensure the container is not abused within the application. – NightOwl888 Feb 09 '15 at 15:28
  • I hadn't figure out that both `IControllerFactory` and `IModelBinder` were somehow part of the composition root. As a matter of fact, I register the new model binder into the `RegisterServices` of the `NinjectWebCommon` App_Start class, so that I wish to make sure I only reference the kernel/container where it belongs. I shall remind these precisions for other projects. – Will Marcouiller Feb 10 '15 at 02:55
  • There is a good article about [DI Friendly Frameworks](http://blog.ploeh.dk/2014/05/19/di-friendly-framework/) that explains why using abstract factory is the best choice for DI integration with MVC, and any framework in general. Just keep in mind that IModelBinder doesn't have a Release method, so if you have IDisposable dependencies of IModelBinder your controller is responsible for cleaning them up. – NightOwl888 Feb 10 '15 at 05:04