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.