1

I'd like to experiment a little bit with the Hybrid Lifestyle in Simple Injector. I'd like to have an optional explicitly defined Async Scope with a fallback to Web Request Scope in case the Async Scope isn't defined.

I'm planning to use this inside ASP.NET MVC controllers where usually I want to resolve instances against the outermost Web Request Scope, but for some situations, I'd like to explicitly create an Async Scope inside the controller's action and have a shorter lifestyle for instances inside the scope.

To explicitly create an Async Scope inside the controller's action, I have to do this:

using (AsyncScopedLifestyle.BeginScope(container))
{
    // ...
}

However, I don't have the container reference inside my controller as it's all set up with DependencyResolver (I'm using ASP.NET MVC 5).


My question is: What is the best way of accessing Simple Injector container inside ASP.NET MVC controller?

Should I register the container instance itself as a service and obtain it through constructor injection in the controller? Or do I create some wrapper around it (e.g. ISimpleInjectorContainerProvider) and get it through there? Or is there some way of getting it through DependencyResolver?

Sorry if this question is a bit stupid, my goal is just to avoid doing some bad practice that could have some negative implications.

2
  • Can you provide more context about why you need a nested scope and show the code that requires it? Commented Feb 18, 2018 at 14:22
  • My plan is to have a nested scope for each business layer transaction. Usually there's either zero or one transaction per web request. But sometimes there are situations where I want to execute multiple transactions after each other in a single web request (it's not needed very often). It would make sense for me to have some objects scoped only to the business layer transaction, so their lifetime starts/ends together with the transaction. Right now, I don't use this approach, so I don't have code to show. But I'd like to try it out, see if it will make sense, experiment with it a little bit... Commented Feb 18, 2018 at 14:40

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for this. I see it's a much better idea to have all DI logic separate from everything else, and this looks like a nice solution. I'll have to spend some time playing with this idea.
The trick sometimes is to think differently. Note that my answer migh actually be not the best solution for your case. My answer is limited by the understanding of your problem and obviously my own limited brain capacity :). That that in mind.
Yes, I get that. I'll probably not end up using this exact solution, but it's a nice illustration of keeping the DI logic inside the composition root. I haven't heard of that concept before, but it feels like a good practice. Also, I wasn't even aware of such an easy way to use decorators, it's good to know. A short answer could be that we can get the Container instance automatically through constructor injection, but I like that you try to explain it a bit further and promote best practices. I see the same principle applied to the design of Simple Injector, and it's a great approach.
A little bit of self promotion here, but you can find a lot more information, basics, patterns en tips and tricks in my upcoming book DI in .NET 2nd edition.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.