1

I'm currently starting ASP.NET MVC 4 and in the book I am reading, the author introduced Ninject for dependency injection. He created a custom dependency resolver (which I don't fully understand how it works, but I think it's use is to easily manage dependency resolution).

Here is the controller code:

public class HomeController : Controller
{
    private Product[] products = {
        new Product {Name = "Kayak", Category = "Watersports", Price = 275M},
        new Product {Name = "Lifejacket", Category = "Watersports", Price = 48.95M},
        new Product {Name = "Soccer ball", Category = "Soccer", Price = 19.50M},
        new Product {Name = "Corner flag", Category = "Soccer", Price = 34.95M}
    };

    private IValueCalculator calc;
    public HomeController(IValueCalculator calcParam)
    {
        calc = calcParam;
    }

    public ActionResult Index()
    {
        ShoppingCart cart = new ShoppingCart(calc) { Products = products };
        decimal totalValue = cart.CalculateProductTotal();
        return View(totalValue);
    }
}

And the custom dependency resolver:

public class NinjectDependencyResolver : IDependencyResolver
{
    private IKernel kernel;
    public NinjectDependencyResolver()
    {
        kernel = new StandardKernel();
        AddBindings();
    }

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

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

    private void AddBindings()
    {
        kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
    }
}

In Application_Start(), the resolver was set:

DependencyResolver.SetResolver(new NinjectDependencyResolver());

Questions:

  1. How did ASP.NET MVC knew what controller constructor to call? I assumed it was going to call the default constructor but there isn't one, I tried adding one, still the constructor with the parameter was called.

  2. How did ASP.NET MVC passed the IValueCalculator to the constructor?

1
  • through the routing config defined. Commented Jul 13, 2014 at 10:52

2 Answers 2

6

This is quote from documentation (https://github.com/ninject/ninject/wiki/Dependency-Injection-With-Ninject):

When asked to instantiate an object, Ninject will look at the type’s available public constructors and pick the one with the most parameters it knows how to resolve — or the parameterless one if there aren’t any suitable ones (there’s an attribute that can be used to override this – see Constructor injection for the nitty gritty).

and another quote from here (https://github.com/ninject/ninject/wiki/Injection-Patterns):

If a constructor has an [Inject] attribute, it is used (but if you
apply the attribute to more than one, Ninject will throw a
NotSupportedException at runtime upon detection).

If no constructors have an [Inject] attribute, Ninject will select the one with the most parameters that Ninject understands how
to resolve.

If no constructors are defined, Ninject will select the default parameterless constructor (assuming there is one).

And how did ASP.NET MVC passed the IValueCalculator to the constructor?

Whole MVC pipeline uses controller factories to build instance of specific controller. Controller factory uses DependencyResolver inside. That is why dependency resolver is registered at application start:

DependencyResolver.SetResolver(new NinjectDependencyResolver());

As I wrote earlier, Ninject knows how to find correct constructor and uses it to build instance. It finds this constructor:

public HomeController(IValueCalculator calcParam)

Here dependency resolver is used to find implementation of IValueCalculator, which was defined here:

private void AddBindings()
{
    kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
}

Ninject here tries one again to find constructor for class LinqValueCalculator. If constructor had dependencies, they would be injected using the same mechanism.

Sign up to request clarification or add additional context in comments.

4 Comments

So TryGet in Ninject is trying to instantiate the HomeController (I previously thought we need to register types to Ninject before it can instantiate it, like IValueCalculator and its implementation, is my understanding correct)? And if what I typed is correct, as you have said Ninject tries to instantiate using the constructor with most parameters that it can resolve. What if I have 2 or more constructors with same number of parameters which Ninject knows how to resolve? Thanks!
@g_b: You don't have to register class types to itself. You have to register interfaces. I don't remember how Ninject behaves with the same number of parateres in constructors. You should generally avoid it or use [Inject] attribute to point correct one.
@LukLed Q1: How is Ninject related to ASP.NET MVC? Q2: Does ASP.NET Core also work the same way?
@OldGeezer: Ninject is not related. This is a very old post. Ninject is a dead library, so you should move on and forget about this answer :)
4

How did ASP.NET MVC know...

It knows by asking the DependencyResolver. MVC will call GetService() when a controller must be created.

The default MVC resolver only handles parametersless constructors, but in your case you have assigned your custom resolver, where the GetService() call will be relayed to NInject's IKernel.TryGet(Type).

NInject will then search for the type HomeController and its constructors, and will find the one with the IValueCalculator parameter.

In the AddBindings() method you have instructed NInject to inject LinqValueCalculator every time a IValueCalculator is required, so it does that, instantiates the type using reflection and returns the initialized controller to MVC.

1 Comment

Thanks, some questions though. Why did it decided to use the HomeController constructor with the IValueCalculator parameter? What if in my AddBindings, I had 2 more bindings (IDiscountHelper, IExampleHelper) and the HomeController has additional 2 more constructor with single parameters also (one accepting IDiscountHelper and the other constructor accepting IExampleHelper). Which one would it choose as the constructor? Also, could you direct me to a resource on how DependencyResolver works/is used by ASP.NET MVC? I've been browsing but I can't seem to find one in the internet.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.