Reputation: 9811
I have a project setup with UnitOfWork Interfaces and Managers. All this works well while I just had to use an accountMananger for the base of my controller.
protected BaseController(IAccountManager acctManager)
{
_accountManager = acctManager;
}
and my controllers are created like this, and works.
public class AccountController : BaseController
{
public AccountController(IAccountManager accountManager)
: base(accountManager)
{
}
Now I am creating other business managers and I realise that by the end of the project my BaseController constructor is going to be huge or I am going to have a load of various signatures based on the controller I am on. And if I forgot something and needed another manager and changes one constructor, all the other controllers need to also change.
I mean, I actually ALWAYS want accountManager to be injected/resolved in the base. Can I do that? Since I am 99% checking for authorisation.
I have read about ControllerFactories but also somebody mentioned to implement IDependancyResolver
, but no example, which is his preferred way to do it.
I can see this becoming a big burden to create constructors based on the controllers I need, which I dont have yet.
Can any body give me an example of how to easily access my managers in the base, as I need them. I mean, they all created and ready to be resolved anyway.. so why the heck do I need to pass them in such a strange way anyway?
Sorry. Just learning about DI and this is from a good tutorial but as you can see lacking some further explanation.
Upvotes: 1
Views: 1709
Reputation: 56849
What you have with your account manager is called a Cross-Cutting Concern. There are a few different ways to skin this cat, but you should avoid injecting the same dependency into every controller.
In general, it is also better to avoid inheritance because that will cause tight coupling between your classes. The tight coupling is obvious here - what if you needed a controller that didn't have IAccountManager
as a dependency later?
In this particular case, there is already a built-in loosely coupled authorization framework in MVC that you can utilize - the AuthorizeAttribute, which is the normal way of handling access to your controller action methods.
[Authorize]
public class AccountController : Controller
{
public AccountController () { . . . }
[AllowAnonymous]
public ActionResult Register() { . . . }
public ActionResult Manage() { . . . }
public ActionResult LogOff() { . . . }
}
There are also several other options for implementing cross-cutting concerns - implementing IActionFilter
- see this for a DI friendly example, interception (which some DI containers support), using the Decorator Pattern, and putting the dependencies in ambient context (such as HttpContext.Items).
I can see this becoming a big burden to create constructors based on the controllers I need, which I dont have yet.
This is why you should inherit DefaultControllerFactory
and provide it with the one instance of your DI container at application startup (in the composition root). It is typically the container's responsibility to provide the dependencies to your controllers, especially if your application is large.
public class AutofacControllerFactory
: DefaultControllerFactory
{
private readonly IContainer container;
public InjectableControllerFactory(IContainer container)
{
if (container == null)
throw new ArgumentNullException("container");
this.container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (requestContext.HttpContext.Request.Url.ToString().EndsWith("favicon.ico"))
return null;
return controllerType == null ?
base.GetControllerInstance(requestContext, controllerType) :
this.container.Resolve(controllerType) as IController;
}
}
I strongly recommend you read the book Dependency Injection in .NET. DI is one of the most misunderstood concepts in software development, and it is well worth the investment of studying the topic in detail on its own without having to sift through the misinformation on the Internet. There are many benefits to be gained by proper use of DI, but improper usage is often worse than not using DI at all.
Upvotes: 2