UnityPerRequestLifetimeManager not disposing

Jun 21, 2011 at 4:00 PM

Hi, 

Is it posible that the UnityPerRequestLifetimeManager Dispose is not being called? ie. DbContext not being disposed?

UnityPerRequestLifetimeManager uses the .EndRequest event to call Dispose but it looks likes that event never gets fired, or received by this class.

Am I missing something?

Thanks in advance

Jun 21, 2011 at 4:05 PM

Ops, just found the comment in HttpContextPerRequestStore:

        public HttpContextPerRequestStore()
        {
            if (HttpContext.Current.ApplicationInstance != null)
            {
                // TODO: re-add this once we figure out how to get around the IIS Integrated pipeline 
                //   providing different instances of the application between app_start and end_request.
                HttpContext.Current.ApplicationInstance.EndRequest += this.EndRequestHandler;
            }
        }

Any news on figuring that out? 

Jun 24, 2011 at 3:12 PM

Benjamine,

The root cause is an issue in ASP.NET.  We are looking into a fix or workaround for this.

Thank you for reporting this and have a great day,

Karl

Jun 24, 2011 at 3:57 PM

Thanks a lot Karl!

Maybe this is not to be included in this discussion, but do you (ie. the P&P Team) have a position about not disposing EF DataContext objects?

Because that's the main object I'm trying to Dispose and I've read that disposing it is not very important after all.

Regards,

Jun 24, 2011 at 10:35 PM

Not sure, will look into it for you.  I'm out until next week.

Best,

Karl

Jul 14, 2011 at 12:10 PM

I would love to know what the official stance on this is as well.

Thanks!

Developer
Jul 14, 2011 at 2:29 PM

Check out the changes in  Drop 13 in globabl.asax.cs that address this.  While the workaround is not as elegant as we would like (and not in the lifetime manager, as we would prefer), it does appear to properly cleanup the per request lifetime objects.

Thanks,
Michael Puleio

Jul 14, 2011 at 2:58 PM

Thanks for the quick reply, so does this mean that the MS stance is to indeed dispose the lifetimemanagers which closes the dbcontext.  I just want to be sure b/c there are so many conflicting views out there on this.

Developer
Jul 19, 2011 at 6:12 PM

I would defer to the Entity Framework team for their recommendation and the "official MS stance".

However, for this project in the way we were using the dbContexts in a per request context, this seemed to be a viable option that did not collapse under our perf and scale testing.  Your project may have different requirements that push you towards other options.

I hope that helps (at least by setting the context for what we did),
Michael Puleio

Sep 24, 2012 at 3:23 PM

Shouldn't the LifetimeManager remove the instance associated with the request when EndRequest fires?  The current code Disposes the LifetimeManager instance instead.  We need to keep the LifetimeManager instance around for the life of the container, right?

        private void EndRequestHandler(object sender, EventArgs e)
        {
            // This is a workaround since subscribing to HttpContext.Current.ApplicationInstance.EndRequest 
            // from HttpContext.Current.ApplicationInstance.BeginRequest does not work. 
            IEnumerable<UnityHttpContextPerRequestLifetimeManager> perRequestManagers = 
                container.Registrations
                    .Select(r => r.LifetimeManager)
                    .OfType<UnityHttpContextPerRequestLifetimeManager>()
                    .ToArray();

            foreach (var manager in perRequestManagers)
            {
                manager.Dispose(); // current code
                // should be this instead?
                // manager.RemoveValue();
            }
        }

I am unfamiliar with the finer points of Unity lifetime management, so a clarification either way is appreciated.

Thanks,

Don

Developer
Sep 28, 2012 at 9:00 PM
Edited Sep 28, 2012 at 9:00 PM

Hi Don,

As far as I know, a new instances of the UnityPerRequestLifetimeManager will be created with each different request made, hence disposing these instances in the EndRequestHandler of each request doesn't seem like a bad approach to me.

For more information on this topic I believe you could find the following resources interesting:

I hope you find this handy,

Agustin Adami
http://blogs.southworks.net/aadami

Oct 1, 2012 at 2:26 PM

Agustin,

Unity LifetimeManager instances are provided during container type registration:

container.RegisterType<IUnitOfWork, HmsDbContext>(new HttpContextPerRequestLifetimeManager());

I provide the Unity container with a single per-request manager for each type resolution.  My UnityHttpContextPerRequestLifetimeManager instances should live as long as the container.  They are not created for each web request.

LifetimeManagers are responsible for storing (SetValue) and freeing (RemoveValue) instances of the registered type at the appropriate time.  That's why it doesn't look quite right that the LifetimeManagers are Disposed at the end of every request.  The LifetimeManagers should dispose any instances of the resolved type associated with that request, right?

Thanks,

Don

Developer
Oct 2, 2012 at 8:13 PM

Hi Don,

In my opinion, how to manager your LifetimeManagers and the corresponding registered instances will depend of the requirements of your scenario and your personal preferences. If in your scenario you are providing a single UnityHttpContextPerRequestLifetimeManager for all the instances of that type, it might make sense to only dispose the instances associated to a request instead of the LifetimeManager itself.

Based on my understanding, in MileageStats's scenario, an instance of UnityHttpContextPerRequestLifetimeManager is created for each registration and for each request. Therefore, it seems that in each request MileageStats have a UnityHttpContextPerRequestLifetimeManager per instance and each manager is only in "charge" of its associated instance. In such scenario, when an instance is removed from the container, it makes sense to dispose the manager too, as it's not in "charge" of any other instance. Then, at the end of a request, MileageStats disposes the corresponding UnityHttpContextPerRequestLifetimeManagers for that request, which also removes the instance from the container in its Dispose method.

This is the approach followed in MileageStats's scenario. If as you mentioned your scenario is different and your LifetimeManagers will be need as long as the container's lifetime, it makes sense to remove only the instances and not the LifetimeManagers. Then again, this will depend of the requirements of your scenario and your personal preferences.

On a side note, as it's name implies, I believe that the UnityHttpContextPerRequestLifetimeManager was designed to be created and disposed in each request. I'm unaware if a single instance of this LifetimeManager can be used for several requests and it might be possible that you will need to modify it with your custom logic to be used in such scenario.

Thanks,

Damian Cherubini
http://blogs.southworks.net/dcherubini

Oct 3, 2012 at 1:02 PM

Damian,

Thanks for the reply.  I am not seeing the LifetimeManager behavior you describe in the MileageStats project.

I see instances of UnityHttpContextPerRequestLifetimeManager created only at application startup when the Unity configuration is loaded.  Unity uses these LifetimeManagers to manage (i.e. SetValue & GetValue) instances of one particular type.  This appears consistent with the one LifetimeManager instance per Unity type registration model.  These LifetimeManagers are Disposed at the termination of every client request, but Unity still holds references.  This was unexpected as I (wrongly) associate Dispose with C++-style destructor semantics and references being released for garbage collection.

After looking at the code more closely I see the Dispose implementation frees the resources (i.e. RemoveValue) associated with the current request only, not all resources managed by that instance.  I missed this initially as I expected Dispose to free all resources associated with an instance.  I switched to calling RemoveValue on my LifetimeManagers at the end of requests.

Thanks for the help,

Don

 

Here is a log with some debug instrumentation I added to track various method calls.  I trimmed this to one instance of UnityPerRequestLifetimeManager, the others are similar:

*** Unity Configuration at app startup
UnityPerRequestLifetimeManager ctor: 7:34:54 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
*** App home page
UnityPerRequestLifetimeManager SetValue: 7:34:56 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb MileageStats.Domain.UserServices
UnityPerRequestLifetimeManager Dispose: 7:34:58 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager RemoveValue: 7:34:58 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb MileageStats.Domain.UserServices
UnityPerRequestLifetimeManager Dispose: 7:34:58 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:34:58 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:34:58 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:34:58 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:34:58 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:34:58 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:34:58 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:34:58 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:34:58 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:34:59 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:34:59 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:34:59 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:34:59 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:34:59 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:34:59 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:34:59 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
*** Login
UnityPerRequestLifetimeManager SetValue: 7:35:55 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb MileageStats.Domain.UserServices
UnityPerRequestLifetimeManager Dispose: 7:35:55 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager RemoveValue: 7:35:55 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb MileageStats.Domain.UserServices
UnityPerRequestLifetimeManager Dispose: 7:35:56 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager SetValue: 7:35:57 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb MileageStats.Domain.UserServices
UnityPerRequestLifetimeManager Dispose: 7:35:58 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager RemoveValue: 7:35:58 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb MileageStats.Domain.UserServices
UnityPerRequestLifetimeManager SetValue: 7:35:58 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb MileageStats.Domain.UserServices
UnityPerRequestLifetimeManager Dispose: 7:36:00 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager RemoveValue: 7:36:00 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb MileageStats.Domain.UserServices
UnityPerRequestLifetimeManager Dispose: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager SetValue: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb MileageStats.Domain.UserServices
UnityPerRequestLifetimeManager Dispose: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager RemoveValue: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb MileageStats.Domain.UserServices
UnityPerRequestLifetimeManager Dispose: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager SetValue: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb MileageStats.Domain.UserServices
UnityPerRequestLifetimeManager SetValue: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb MileageStats.Domain.UserServices
UnityPerRequestLifetimeManager Dispose: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager Dispose: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager RemoveValue: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb MileageStats.Domain.UserServices
UnityPerRequestLifetimeManager Dispose: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb
UnityPerRequestLifetimeManager RemoveValue: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb MileageStats.Domain.UserServices
UnityPerRequestLifetimeManager Dispose: 7:36:01 AM ffc6748e-2e45-4ccd-9da7-c28f0c1fffcb