Question

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!

Was it helpful?

Solution

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

OTHER TIPS

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>();

I've taken a somewhat different (but to me, fairly obvious and probably common) approach. It works for me, but there may be pitfalls I'm not aware of.

I have created common service properties in my BaseController class that most of my controllers use. They get instantiated when they are needed/referenced.

If there's a service a particular controller needs that is less used, I inject it into that controller's constructor as normal.

using JIS.Context;
using JIS.Managers;
using JIS.Models;
using JIS.Services;
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;

namespace JIS.Controllers
{
    public class BaseController : Controller
    {
        public BaseController()
        {
            ViewBag.User = UserManager?.User;
        }

        private IUserManager userManager;
        public IUserManager UserManager
        {
            get
            {
                if (userManager == null)
                {
                    userManager = DependencyResolver.Current.GetService<IUserManager>();
                }
                return userManager;
            }
            set
            {
                userManager = value;
            }
        }

        private ILoggingService loggingService;
        public ILoggingService LoggingService
        {
            get
            {
                if (loggingService == null)
                {
                    loggingService = DependencyResolver.Current.GetService<ILoggingService>();
                }
                return loggingService;
            }
            set { loggingService = value; }
        }

        private IUserDirectory userDirectory;
        public IUserDirectory UserDirectory
        {
            get
            {
                if (userDirectory == null)
                {
                    userDirectory = DependencyResolver.Current.GetService<IUserDirectory>();
                }
                return userDirectory;
            }
            set { userDirectory = value; }
        }

        private ApplicationDbContext appDb;
        public ApplicationDbContext AppDb
        {
            get
            {
                if (appDb == null)
                {
                    appDb = new ApplicationDbContext();
                }
                return appDb;
            }
            set
            {
                appDb = value;
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing && appDb != null)
            {
                appDb.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}

In my controller I simply subclass from this BaseController:

public class UsersController : BaseController
{
    // and any other services I need are here:
    private readonly IAnotherService svc;
    public UsersController(IAnotherService svc)
    {
        this.svc = svc;
    }
...
}

This way, common services are generated on the fly when they're needed, and are available to my controllers without a lot of boilerplate.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top