How tell to Container Dispose Objects after a Request End - MVC 3.0

Jan 19, 2011 at 11:45 PM

I am using ASP.NET MVC 3, and at Application_Start I do this:

            container.RegisterType<IUserRepositoryUserRepository>();
            container.RegisterType<IPostRepositoryPostRepository>(); 
            DependencyResolver.SetResolver(new UnityDependencyResolver(container));

But I need to create one repository by request, and guarantee that it is Disposed at Request End
Jan 24, 2011 at 7:06 PM

I have implemented the example per web request as below, but it doesn't ever seem to actually call dispose....

    public class HttpContextLifetimeManager : LifetimeManager, IDisposable
    {
        const string ItemName = "HttpContextLifetimeManager";


        public override object GetValue()
        {
            return HttpContext.Current.Items[ItemName];
        }
        public override void RemoveValue()
        {
            HttpContext.Current.Items.Remove(ItemName);
        }

        public override void SetValue(object newValue)
        {
            HttpContext.Current.Items[ItemName] = newValue;
        }
        public void Dispose()
        {
            RemoveValue();
        }
    }
I use this lifetime manager when creating the dependencies, as so:
protected void RegisterTypes()
{
    unityContainer.RegisterType<IUnitOfWork, EFUnitOfWork>(new HttpContextLifetimeManager());
    unityContainer.RegisterType<IRepository<ShoppingCart>, ShoppingCartRepository>();
}
But dispose never gets called...Any ideas?
Jan 24, 2011 at 7:10 PM

After some analysis of this, just because the lifetime manager implements IDisposable, there's nothing to say that Dispose() actually gets called.  I tried the below instead, but still no bones:

 

    public class HttpContextDisposableLifetimeManager : LifetimeManager, IDisposable
    {
        const string ItemName = "HttpContextLifetimeManager";


        public override object GetValue()
        {
            return HttpContext.Current.Items[ItemName];
        }
        public override void RemoveValue()
        {
            Dispose();
            HttpContext.Current.Items.Remove(ItemName);
        }

        public override void SetValue(object newValue)
        {
            HttpContext.Current.Items[ItemName] = newValue;
        }
        public void Dispose()
        {
            var obj = (IDisposable)GetValue();
            obj.Dispose();
        }
    }

Jan 24, 2011 at 7:54 PM

So what this code is doing is registering the instance names in the HttpContext, so that when the request is over, the collection is lost, and a new instance must be created.  The problem is that when the context is over, it still doesn't call dispose.  Simply implementing the interface isn't any good.

The solution would be to create a method in the lifetime manager to track the HttpContext, and call dispose on it's registered instances when the HttpContext finishes.

 

Jan 24, 2011 at 9:10 PM

Or write some code in your Request_End handler to walk through the items in the context and call dispose on them.

 

Jan 24, 2011 at 10:33 PM
ctavares wrote:

Or write some code in your Request_End handler to walk through the items in the context and call dispose on them.

 

 I try this, but dont work:

 

        protected void Application_EndRequest(object sender, EventArgs e)
        {
            foreach (IDisposable disposable in DependencyResolver.Current.GetServices<IDisposable>())
            {
                disposable.Dispose();
            }
        }

And which nomadixone HttpContextLifetimeManager implementation is more correct?

Thx

 

Jan 24, 2011 at 11:17 PM

I look this topic and try do adapt to ASP.NET MVC 3. I dont know if is all correct. http://unity.codeplex.com/Thread/View.aspx?ThreadId=38588

And why dont work if I register types at parent container. I need always to register at child container, per request. In really if I need to register every time, I dont need a parent....

        protected void Application_Start()
        {
            ConfigureUnity();
        }

        private static void ConfigureUnity()
        {
            var container = new UnityContainer();//In really never used
            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        }

        protected void Application_EndRequest(object sender, EventArgs e)
        {
            using (DependencyResolver.Current as IDisposable) ;
        }

 public class UnityDependencyResolver : IDependencyResolverIDisposable
    {
        private readonly IUnityContainer parentContainer;

        private IUnityContainer Container
        {
            get
            {
                IUnityContainer container = HttpContext.Current.Items["Container"as IUnityContainer;
                if (container == null)
                {
                    container = parentContainer.CreateChildContainer();
                    container.RegisterType<FujiyBlogDatabaseFujiyBlogDatabase>(new ContainerControlledLifetimeManager());
                    container.RegisterType<IUnitOfWorkFujiyBlogDatabase>(new ContainerControlledLifetimeManager());
                    container.RegisterType<IUserRepositoryUserRepository>(new ContainerControlledLifetimeManager());
                    container.RegisterType<IPostRepositoryPostRepository>(new ContainerControlledLifetimeManager());
                    container.RegisterType<IPostCommentRepositoryPostCommentRepository>(new ContainerControlledLifetimeManager());
                    HttpContext.Current.Items["Container"] = container;
                }
                return container;
            }
        }

        public UnityDependencyResolver(IUnityContainer container)
        {
            parentContainer = container;
        }

        public object GetService(Type serviceType)
        {
            if ((serviceType.IsClass && !serviceType.IsAbstract) || Container.IsRegistered(serviceType))
                return Container.Resolve(serviceType);
            return null;
        }


        public IEnumerable<object> GetServices(Type serviceType)
        {
            if ((serviceType.IsClass && !serviceType.IsAbstract) || Container.IsRegistered(serviceType))
                return Container.ResolveAll(serviceType);

            return new object[] {};
        }

        public void Dispose()
        {
            Container.Dispose();
        }
    }


Jan 24, 2011 at 11:33 PM

I'm of the mind that my second implementation is more correct, but again, since the unity container is instantiated in application on start, it would have application scope, and would only explicitly remove the object from the lifetime manager on app shutdown, instead of when the request finishes. 

Also, simply looping through the dependency resolver will not yield the items that implement the IDisposable interface will not work, since you didn't register them this way and unity doesn't track things like that.  The solution I came up with looks like the following, but still doesn't work:

 

    public class HttpContextDisposableLifetimeManager : LifetimeManager, IDisposable
    {
        const string ItemName = "HttpContextLifetimeManager";

        public void DisposingHandler(object source, EventArgs e)
        {
            RemoveValue();
        }

        public override object GetValue()
        {
            return HttpContext.Current.Items[ItemName];
        }
        public override void RemoveValue()
        {
            Dispose();
            HttpContext.Current.Items.Remove(ItemName);
        }

        public override void SetValue(object newValue)
        {
            HttpContext.Current.Items[ItemName] = newValue;
        }
        public void Dispose()
        {
            var obj = (IDisposable)GetValue();
            obj.Dispose();
        }
    }
from the globals file:
        protected void RegisterTypes()
        {
            var ltm = new HttpContextDisposableLifetimeManager();
            this.EndRequest += new EventHandler(ltm.DisposingHandler);
            unityContainer.RegisterType<IUnitOfWork, EFUnitOfWork>(ltm);
            unityContainer.RegisterType<IRepository<UPGSysproPortal.BLL.Objects.ShoppingCart>, ShoppingCartRepository>();
        }
But a breakpoint set on the dispose method never gets hit, nor does the remove method...
Jan 24, 2011 at 11:37 PM

As for what I understand about the parent and child contexts is that you create the children so that you may dispose of them without disposing of the parent, which has a lifetime of the entire application scope.  That way you can call dispose on the child container, and at that point you would expect to be able to iterate through all of the instances held by the child context that can be disposed, and dispose them.

Jan 24, 2011 at 11:54 PM
fujiy wrote:
ctavares wrote:

Or write some code in your Request_End handler to walk through the items in the context and call dispose on them.

 

 I try this, but dont work:

 

        protected void Application_EndRequest(object sender, EventArgs e)
        {
            foreach (IDisposable disposable in DependencyResolver.Current.GetServices<IDisposable>())
            {
                disposable.Dispose();
            }
        }

And which nomadixone HttpContextLifetimeManager implementation is more correct?

Thx

 

You should be looping through HttpContext.Current.Items, not DependencyResolver.Current.GetServices. This will call dispose on anything in the context that's about to go away anyway. Doing what you're doing now isn't going to work at all - nothing's registered in the container as type IDisposable, so it'll return an empty collection. And even if it did, that would cause all sorts of stuff to break.

 

 

Jan 25, 2011 at 2:17 AM

I did this, it´s simple and work, disposing objects:

 

        protected void Application_Start()
        {
            DependencyResolver.SetResolver(new UnityDependencyResolver());
        }

        protected void Application_EndRequest(object sender, EventArgs e)
        {
            using (DependencyResolver.Current as IDisposable) ;
        }

 

    public class UnityDependencyResolver : IDependencyResolverIDisposable
    {
        private static IUnityContainer Container
        {
            get
            {
                IUnityContainer container = HttpContext.Current.Items["Container"as IUnityContainer;
                if (container == null)
                {
                    container = new UnityContainer();
                    container.RegisterType<FujiyBlogDatabaseFujiyBlogDatabase>(new ContainerControlledLifetimeManager());
                    container.RegisterType<IUnitOfWorkFujiyBlogDatabase>(new ContainerControlledLifetimeManager());
                    container.RegisterType<IUserRepositoryUserRepository>(new ContainerControlledLifetimeManager());
                    container.RegisterType<IPostRepositoryPostRepository>(new ContainerControlledLifetimeManager());
                    container.RegisterType<IPostCommentRepositoryPostCommentRepository>(new ContainerControlledLifetimeManager());
                    HttpContext.Current.Items["Container"] = container;
                }
                return container;
            }
        }

        public object GetService(Type serviceType)
        {
            if ((serviceType.IsClass && !serviceType.IsAbstract) || Container.IsRegistered(serviceType))
                return Container.Resolve(serviceType);
            return null;
        }


        public IEnumerable<object> GetServices(Type serviceType)
        {
            if ((serviceType.IsClass && !serviceType.IsAbstract) || Container.IsRegistered(serviceType))
                return Container.ResolveAll(serviceType);

            return new object[] {};
        }

        public void Dispose()
        {
            Container.Dispose();
        }
    }

 

Jan 25, 2011 at 8:05 PM

My solution looks more like the following, and it does work, but it does seem a little hackish.  I use my custom lifetime manager only to wrap my entity framework unit of work context wrapper, and the standard container controlled lifetime manager for the rest.  My repositories are constructor injected with the unit of work, and it disposes nicely when the request completes.

First snippet from the globals.asax.cs file, the second from my custom lifetime manager class

public class MvcApplication : HttpApplication
{
    private IUnityContainer unityContainer;
    private HttpContextDisposableLifetimeManager ContextLifeTimeManager;
    /// <summary>
	/// The start method of the application.
	/// </summary>
	protected void Application_Start()
	{
        unityContainer = new UnityContainer();
        ContextLifeTimeManager = new HttpContextDisposableLifetimeManager();
        //for some reason this event handler registration doesn't work, meaning we have to add code to
        //Application_EndRequest as below...
        //this.EndRequest += new EventHandler(ContextLifeTimeManager.DisposingHandler);
        unityContainer.RegisterType<IUnitOfWork, EFUnitOfWork>(ContextLifeTimeManager);
        unityContainer.RegisterType<IRepository<ShoppingCart>, ShoppingCartRepository>(new ContainerControlledLifetimeManager());
    }
    //this seems hackish, but it works, so whatever...
    protected void Application_EndRequest(Object sender, EventArgs e)
    {
        if (ContextLifeTimeManager != null)
        {
            ContextLifeTimeManager.RemoveValue();
        }
    }
}
public class HttpContextDisposableLifetimeManager : LifetimeManager, IDisposable
{
    //since this is a constant string, you can only instantiate one of these
    const string ItemName = "HttpContextLifetimeManager";

    public void DisposingHandler(object source, EventArgs e)
    {
        RemoveValue();
    }

    public override object GetValue()
    {
        return HttpContext.Current.Items[ItemName];
    }
    public override void RemoveValue()
    {
        Dispose();
        HttpContext.Current.Items.Remove(ItemName);
    }

    public override void SetValue(object newValue)
    {
        HttpContext.Current.Items[ItemName] = newValue;
    }
    public void Dispose()
    {
        var obj = (IDisposable)GetValue();
        obj.Dispose();
    }
}
 
 

Mar 31, 2011 at 1:13 PM
Edited Apr 1, 2011 at 9:05 AM

You might like to try http://unitymvc3.codeplex.com which takes care of all this for you in a simple and efficient manner. It is also available as a NuGet package (Unity.Mvc3)