StructureMap is not disposing data context when using HttpContextScoped()
Asked Answered
G

2

10

My goal is to have one data context (MainDbContext) per HTTP request in ASP.NET MVC and dispose the data context when the request ends.

I'm using the following StructureMap configuration:

public static class ContainerConfigurer
{
    public static void Configure()
    {
        ObjectFactory.Initialize(x =>
        {
            x.For<MainDbContext>().HttpContextScoped();
        });
    }
}

Whenever I need a MainDbContext, I'm using this code:

var dbContext = ObjectFactory.GetInstance<MainDbContext>();

This is working as expected: only one data context is being created per HTTP request. The problem is, MainDbContext is not being disposed at the end of the request.

How can I configure my ObjectFactory to dispose the data context when the HTTP request finishes? Or is this just something I need to do manually using Application_EndRequest() in Global.asax.

Update

I just tried adding the following code to Global.asax:

protected virtual void Application_EndRequest()
{
    ObjectFactory.GetInstance<MainDbContext>().Dispose();
}

As expected, this solves the problem. I'm still wondering if there's any way to do this automatically with StructureMap, however.

Garpike answered 17/6, 2011 at 19:7 Comment(0)
N
9

Instead of:

x.For<MainDbContext>().HttpContextScoped();

Try:

x.For<MainDbContext>().HttpContextScoped().Use(() => new MainDbContext());

Also normally it's repository classes that need a db context. So instead of ObjectFactory.GetInstance<MainDbContext>(); have your repositories take some interface db context and configure StructureMap to inject the MainDbContext into them. Then make StructureMap inject repositories into controllers, ...

In Application_EndRequest:

protected void Application_EndRequest()
{
    ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
}
Nectarine answered 17/6, 2011 at 19:12 Comment(4)
makes no difference. Dispose() is still not being called.Garpike
I already am injecting a data context into my repositories/services as you suggest. The problem is, I also have ActionFilters, Validators, and a MembershipProvider that require a data context, and since these objects are instantiated automatically by ASP.NET MVC (just as controllers are), I'm using StructureMap to manage the lifetime of my data context. If you have a better solution, please let me know.Garpike
@DanM, you are correct, I've tested it and it seems that StructureMap doesn't automatically dispose IDisposable HttpContext scoped objects at the end of the request. Calling ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects in Application_EndRequest is probably the best way to ensure that this happens for all objects.Nectarine
When I call the 'ReleaseAndDisposeAllHttpScopedObjects' method, it's just a part of the solution for me; I must also add a manual dispose of the unit of work (LightSpeed) like that: StructureMap.ObjectFactory.GetInstance<MyUnitOfWork>().Dispose(). I'm not sure exactly why but if I don't call the last one, the unit of works are not disposed and connections not released.Stu
A
5

Using a nested container is the only way to get Structure Map to automatically dispose objects. If you're not using that technique the only way is to dispose the objects yourself using either the way the OP described (pulling the object from the container and disposing it; see this NHibernate example for one way to do it) or to scope the object to HttpRequest and call ReleaseAndDisposeAllHttpScopedObjects as Darin described.

Aerostatics answered 18/6, 2011 at 12:12 Comment(6)
+1 and thanks, PHeiberg. The nested container looks like an interesting solution, but if I used the code sample you linked to for my situation, I believe it would dispose my data context several times per request. My goal is to have just one data context per request. It also looks like it would result in a lot more code. So, I think I'll stick with Darin's solution. Please correct me if I'm misunderstanding.Garpike
When using a nested container you would create one instance of the nested container per request and dispose of it at the end of the request. Disposing a nested container will dispose all transient objects created within it. I haven't seen any examples of using nested containers with ASP.NET MVC or Webforms. Jeremy's example is using Fubu and NHibernate (codebetter.com/jeremymiller/2010/01/06/…). For simple scenarios Darin's or your way are probably the easiest. I have used them for all my web applications with SM.Aerostatics
I would just add as mentioned in the linked article that the nested container “pulls” all instances scoped as anything but transients (Singletons, HttpContext scoped objects, ThreadLocalStorage scoped objects, etc.) from the parent container. These objects are not disposed from the nested container. So if my understanding is good, the HttpContextScoped objects won't be disposed anyway.Forsaken
@ThomasJaskula - when using a nested container you would scope the Db Context as transient in the nested container, not HttpContextScoped.Aerostatics
PHeiberg, thanks for clarification I'm not native english speaker. So does this mean that DbContext when pulled from the child container will have a transcient lifetime and disposed when the child container will be disposed. Even if DbContext was registered with HttpContextSoped lifetime ?Forsaken
@ThomasJaskula - You should register the DbContext as transient. The DbContext will then be disposed when the nested container is disposed. If you register it as HttpContextScoped, the instance will not be disposed when disposing the nested container.Aerostatics

© 2022 - 2024 — McMap. All rights reserved.