Per Request lifetime is one of the lifetimes that Simple Injector supports (as you would expect). But there is a bit of a problem when it comes to resolving objects in the application’s Application_EndRequest of the Global.asax.cs. Fortunately, the author of Simple Injector has built in a callback which effectively enables us to do the same thing. Other containers solve the problem differently (e.g. StructureMap offers Nested Containers). I also want to point out that Steven van Deursen (aka .NET junkie) is one of the most helpful developers on the planet. He freely gives away design/architectural advice and is very active answering questions about Simple Injector. The kind of guy I would love to work with.
Anyhow, lets say we have the following code which we want to run in the Application_EndRequest event handler (e.g. IRunAfterEachRequest may be implemented by a transaction-per-request object which either commits or rolls back a transaction at the conclusion of the request):
public void Application_EndRequest()
{
foreach (var task in DependencyResolver.Current.GetServices(typeof(IRunAfterEachRequest)).Cast<IRunAfterEachRequest>())
{
task.Execute();
}
}
You are going to get an exception:
[ObjectDisposedException: Cannot access a disposed object.
Object name: ‘SimpleInjector.Scope’.]
The reason being that the Container disposes the Scope by hooking into the HttpContext.EndRequest event. And that event gets handled before the Application_EndRequest.
The solution to the problem is to put the code, which you would otherwise put in the Application_EndRequest handler, in the WhenScopeEnds callback which I mentioned at the top of the post. And this would be done, ironically, in the Application_BeginRequest handler:
public void Application_BeginRequest()
{
var container = SimpleInjectorInitializer.Container;
container.Options.DefaultScopedLifestyle.WhenScopeEnds(container, () =>
{
foreach (var task in container.GetAllInstances<IRunAfterEachRequest>())
{
task.Execute();
}
});
foreach (var task in container.GetAllInstances<IRunOnEachRequest>())
{
task.Execute();
}
}
Note that I have exposed the Container as a static property of the SimpleInjectorInitializer class.
This is all explained in more detail here.