Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Base controller constructor injection in ASP.NET MVC with Unity

I have a base controller in my MVC 5 project which implements some shared functionality. This functionality requires some dependencies. I am using Unity 3 to inject these implementations into my controllers, a pattern which has worked fine until I switched my controllers to inherit from this base controller. Now I am running into the following issue:

public class BaseController : Controller {     private readonly IService _service;      public BaseController(IService service)     {         _service = service;     } }  public class ChildController : BaseController {     private readonly IDifferentService _differentService;      public ChildController(IDifferentService differentService)     {         _differentService = differentService;     } } 

This is understandably throwing an error of 'BaseController' does not contain a constructor that takes 0 arguments. Unity is not resolving the construction of the BaseController, so it can't inject the dependencies into it. I see two obvious ways of solving this issue:

1.) Explicitly call the BaseController ctor and have each ChildController ctor inject the BaseController's dependencies

public class ChildController : BaseController {     private readonly IDifferentService _differentService;      public ChildController(IDifferentService differentService,                            IService baseService)         : base(baseService)     {         _differentService = differentService;     } } 

I don't like this approach for several reasons: one, because the ChildControllers are not making use of the additional dependencies (so it causes constructor bloat in the child controllers for no reason), and more importantly, if I ever change the constructor signature of the Base Controller, I have to change the constructor signatures of each child controller.

2.) Implement the BaseController's dependencies via property injection

public class BaseController : Controller {     [Dependency]     public IService Service { get; set; }      public BaseController() { } } 

I like this approach better - I'm not using any of the dependencies in the BaseController's constructor code - but it makes the dependency injection strategy of the code inconsistent, which isn't ideal either.

There's probably an even better approach which involves some sort of BaseController dependency resolution function that calls on the Unity container to sort out the ctor's method signature, but before I get into writing anything too involved, I was wondering if anyone had solved this problem before? I found a few solutions floating around on the web, but they were workarounds such as Service Locator which I don't want to use.

Thanks!

like image 558
NWard Avatar asked Feb 20 '14 18:02

NWard


People also ask

How does constructor injection work C#?

Constructor Injection Dependency Injection is done by supplying the DEPENDENCY through the class's constructor when creating the instance of that class. The injected component can be used anywhere within the class. Recommended to use when the injected dependency, you are using across the class methods.

What is base controller in MVC?

Mvc. Controller . Controller class contains public methods called Action methods. Controller and its action method handles incoming browser requests, retrieves necessary model data and returns appropriate responses.

What is constructor in ASP NET MVC?

A constructor is a special type of method of a C# class which invokes automatically when a new instance of a class is created. Constructor is used in object initialization and memory allocation of the class. Constructor is used to initialize private fields and their values of the class. A constructor can be overloaded.


2 Answers

The first thing you have to understand is that you aren't instantiating the base controller. You're instantiating the child controller, which inherits the base controllers interface and functionality. This is an important distinction. When you say "the ChildControllers are not making use of the additional dependencies", then you're absolutely wrong. Because the ChildController IS the BaseController as well. There aren't two different classes created. Just one class that implements both functionality.

So, since ChildController IS A BaseController, there is nothing wrong or strange about passing parameters in the child controllers constructor that calls the base classes constructor. This is the way it should be done.

If you change your base class, you will likely have to change your child classes anyways. There is no way to use constructor injection to inject base class dependencies that are not included in the child class.

I do not recommend property injection, since this means your objects can be created without proper initialization, and you have to remember to configure them correctly.

BTW, the proper terms are Subclass and Superclass. A "child" is a subclass, the parent is the "superclass".

like image 199
Erik Funkenbusch Avatar answered Oct 11 '22 02:10

Erik Funkenbusch


With ASP.Net 5 and it's built in DI

public class BaseController : Controller {     protected ISomeType SomeMember { get; set; }      public BaseController(IServiceProvider serviceProvider)     {         //Init all properties you need         SomeMember = (SomeMember)serviceProvider.GetService(typeof(ISomeMember));     } }  public class MyController : BaseController   { public MyController(/*Any other injections goes here*/,                        IServiceProvider serviceProvider) :   base(serviceProvider) {} } 

UPDATE

There is also an extension method in Microsoft.Extensions.DependencyInjection to make it shorter

SomeMember = serviceProvider.GetRequiredService<ISomeMember>(); 
like image 22
Vitaly Avatar answered Oct 11 '22 03:10

Vitaly