This project is read-only.

Registration that references the container

Sep 3, 2014 at 3:24 PM
With most IOC containers I've used, when registering a function that must itself resolve a container instance internally, the registration delegate contains a reference to the scoped container...something like what is below (pseudocode). Often this is because a child container is created within the specified scope, so it doesn't make sense to ask the parent container for the instance as it would be scoped incorrectly) Ex as I've seen in some containers:
container.RegisterWebApiRequest<Func<IUnitOfWork>>((__scopeReference__) => __scopeReference__.GetInstance<IUnitOfWork>());
The examples I see everywhere with Simple Injector just use the parent container in the registration process, like:
container.RegisterWebApiRequest<Func<IUnitOfWork>>(() => container.GetInstance<IUnitOfWork>());
The question is: Will this take the correct container lifetime scope into account when resolving the contained GetInstance? If not, how this is done in SimpleInjector?
Sep 3, 2014 at 4:00 PM
Edited Sep 3, 2014 at 9:33 PM
Yep, this works as expected in Simple Injector. We deliberately selected a design where such scope is not needed in the delegates. This made a lot of things A LOT more difficult internally for us, but makes things much easier for the user that doesn't has to pass those scopes around. The registration gets more readable this way and in some cases it very hard to impossible to pass on the scope. In Simple Injector this is something you don't have to worry about. In the background Simple Injector will always find the correct scope for you. Take this example for instance:
using (var scope = container.BeginLifetimeScope())
{
    // Notice the use of 'container' instead of 'scope'.
    container.GetInstance<IUnitOfWork>();
}
The lifetime scope is thread-specific, and Simple Injector will find currently active scope by going to its internal ThreadLocal<Scope> variable that is registered in the container.

Or this example:
using (container.BeginExecutionContextScope())
{
    var uow1 = container.GetInstance<IUnitOfWork>();
    await SomeAsyncOperation();
    var uow2 = container.GetInstance<IUnitOfWork>();
    await SomeOtherAsyncOperation();

    Assert.AreEqual(uow1, uow2);
}
The same applies here, but now for the execution scope, which flows over asynchronous methods. Here the scope is stored in the ExecutionContext and the container will fetch the proper scope instance for you, and: throw an exception when such scope does not exist (where most containers will return you 'something', which is a source of bugs).

It might seem that by selecting this design, Simple Injector is much slower, but we know that this is not the case. Even though loading data from ThreadLocal<T> and ExecutionContext are relatively heavy, Simple Injector optimizes this internally to prevent having to request the same scope multiple times in same object graph, by optimizing the expression tree before it gets compiled.

Long story short, container.RegisterWebApiRequest<Func<IUnitOfWork>>(() => container.GetInstance<IUnitOfWork>()); is correct and scoping is automatically handled for you by Simple Injector.
Marked as answer by dot_NET_Junkie on 9/3/2014 at 11:28 AM
Sep 3, 2014 at 7:18 PM
Nice, thanks for the thorough answer!