2

I have an MVC Controller with many different Actions. I use Ninject for dependency injection.

Each action requires some specific dependencies.

How is it better to inject these dependencies?

  1. Inject all of them in the Controller, and use the ones i need.

  2. Inject only IKernel in Controller, and get the dependencies in the current action which is executed.

I think that approach #2 is better, because i can avoid creating some dependencies that will not be used.

Example 1:

public class MyController : Controller
{
    private readonly IService1 _service1;
    private readonly IService2 _service2;
    private readonly IService3 _service3;
    public MyController(IService1 service1, IService2 service2, IService3 service3)
    {
        _service1 = service1;
        _service2 = service2;
        _service3 = service3;
    }

    public ActionResult Action1()
    {
        _service1.Get();
        return View();
    }

    public ActionResult Action2()
    {
        _service2.Get();
        return View();
    }

    public ActionResult Action3()
    {
        _service3.Get();
        return View();
    }
}

Example 2:

public class MyController : Controller
{
    private readonly IKernel _kernel;
    public MyController(IKernel kernel)
    {
        _kernel = kernel;
    }

    public ActionResult Action1()
    {
        IService1 _service1 = _kernel.Get<IService1>();
        _service1.Get();

        return View();
    }

    public ActionResult Action2()
    {
        IService2 _service2 = _kernel.Get<IService2>();
        _service2.Get();

        return View();
    }

    public ActionResult Action3()
    {
        IService3 _service3 = _kernel.Get<IService3>();
        _service3.Get();

        return View();
    }
}
Catalin
  • 11,503
  • 19
  • 74
  • 147
  • 1
    [Service locator is anti-pattern](http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/). Never inject the container anywhere except for [infrastructure components](http://blog.ploeh.dk/2011/08/25/ServiceLocatorrolesvs.mechanics/). That means Controllers are a no-go. Sure, it may be easier to make controllers this way, but you more than pay the price in maintenance when you need to figure out what a controller depends on. – NightOwl888 Mar 13 '17 at 21:05
  • I know using a Service locator is bad, especially because you can be tempted to send only the Service locator as a dependency for all your Services. The only exception i can think about would be at the application entry point, which in this case would only be the Controllers – Catalin Mar 13 '17 at 21:15
  • The Controllers are _not_ in the application's entry point. Controllers live in your UI layer, which is a different layer than your application's entry point. You can find a more thorough explanation about this [here](https://stackoverflow.com/a/9505530/264697). – Steven Mar 13 '17 at 21:23
  • 1
    Note that if your controllers have a large set of dependencies, where each action has its own _set_ of dependencies that is not used by other actions, it means that the methods in the controller have _low cohesion_ and this is an indication of a **Single Responsibility Principle** violation. In that case it might be better to split your Controller into multiple smaller controllers. – Steven Mar 13 '17 at 21:26

2 Answers2

3

As you already know, example #2 is Service Locator Pattern. Many of us used it in ASP.Net Web Form in good old days - we didn't know any better back then.

However, better alternatives exists for ASP.Net MVC such as Constructor Injection - a default goal for DI - example #1.

Service Locator has few problems. One of them is it doesn't follow Don't call us, we'll call you principle. Instead, we directly ask for the things we need rather than handed them to us.

With the service locator, we have to examine the code, searching for capricious calls that retrieve a required service. Constructor injection allowed us to view dependencies—all of them—with a glance at the constructor, or at a distance, via IntelliSense.

Source: Dependency Injection in .NET by Mark Seemann and Adaptive Code via C# by Gary McLean Hall

Win
  • 61,100
  • 13
  • 102
  • 181
1

What you are describing is using Ninject's IKernel as a Service Locator, which defined by Mark Seemann is an anti-pattern (source)

Service Locator is a well-known pattern, and since it was described by Martin Fowler, it must be good, right?

No, it's actually an anti-pattern and should be avoided.

He explains with details and examples why Service Locator is an anti-patern, eg.

  • API usage issues
  • Maintenance issues

You can also see this question for more info

Community
  • 1
  • 1
Maximo Dominguez
  • 2,075
  • 18
  • 35