What is the best way of accessing Simple Injector container inside ASP.NET MVC controller?
The best way of accessing the container within a controller is to don't.
The only place in your application that should access your DI Container, or an abstraction thereof (such as a Service Locator or DependencyResolver) is the Composition Root.
MVC Controllers however are not part of the Composition Root, they are part of the presentation layer. Depending on the DI Container or any construct that related to it is a bad idea.
Instead, By using Abstractions, Dependency Injection provides us with a way to intercept method calls by using decorators.
This allows you to define a decorator inside the Composition Root, and let it control scoping, before forwarding the call to the wrapped service.
Say for instance your OrderController depends on an IOrderService as follows:
public class OrderController : Controller
{
private readonly IOrderService service;
public ProductController(IOrderService service)
{
this.service = service;
}
[Post]
public ActionResult CancelOrder(Guid orderId)
{
this.service.CancelOrder(orderId);
return this.Ok();
}
}
In case the CancelOrder operation needs to run in its own isolated scope, instead of letting the OrderController handle this, we should move this responsibility to a different class. Since moving it into the OrderService implementation is a bad idea as well, we can place this behavior in a decorator:
// This class depends on the Container and should therefore be part of
// your Composition Root
public class ScopingOrderServiceDecorator : IOrderService
{
// Depend on the Container
private readonly Container container;
// Wrap a Func<IOrderService>. This allows the 'real' `IOrderService`
// to be created by the container within the defined scope.
private readonly Func<IOrderService> decorateeFactory;
ScopingOrderServiceDecorator(Container container, Func<IOrderService> decorateeFactory)
{
this.container = container;
this.decorateeFactory = decorateeFactory;
}
public void CancelOrder(Guid orderId)
{
// Create a new scope
using (AsyncScopedLifestyle.BeginScope(this.container))
{
// Within the scope, invoke the factory. That ensures an instance
// for this scope.
IOrderService decoratee = this.decorateeFactory.Invoke();
// Forward the call to the created decoratee
decoratee.CancelOrder(orderId);
}
}
}
By using a decorator you leave both the controller and the actual business logic untouched, and allows you to add this behavior just by making changes to your Composition Root.
You can register this in Simple Injector as follows:
container.Register<IOrderService, OrderService>();
container.RegisterDecorator<IOrderService, ScopingOrderServiceDecorator>();
Simple Injector will automatically inject itself in a constructor when it sees a constructor argument of type SimpleInjector.Container. You don't have make any special registrations for that. However, as stated above, only classes that are part of your Composition Root should take a dependency on the Container, so don't go sprinkling the Container throughout your code base. That will lead to code that is hard to maintain, and hard to test.
Simple Injector considers the Func<IOrderService> to be a special kind of dependency. Typically, Simple Injector will not inject Func<T> dependencies automatically, but decorators are the exception to this rule. Simple Injector ensures that the injected Func<T> can resolve the 'real' implementation.