Base controller constructor injection in ASP.NET MVC with Unity

37,968

Solution 1

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".

Solution 2

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>();
Share:
37,968
NWard
Author by

NWard

Updated on November 30, 2020

Comments

  • NWard
    NWard over 3 years

    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!