84

I'm going through a big refactoring / speed tweaking of one of my larger MVC apps. It has been deployed to production for a few months now, and I was starting to get timeouts waiting for connections in the connection pool. I have tracked the issue down to the connections not getting disposed properly.

In light of that, I have since made this change to my base controller:

public class MyBaseController : Controller
{
    private ConfigurationManager configManager;  // Manages the data context.

    public MyBaseController()
    {
         configManager = new ConfigurationManager();
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (this.configManager != null)
            {
                this.configManager.Dispose();
                this.configManager = null;
            }
        }

        base.Dispose(disposing);
    }
}

Now, I have two questions:

  1. Am I introducing a race condition? Since the configManager manages the DataContext that exposes IQueryable<> parameters to the views, I need to make sure that Dispose() will not be called on the controller before the view finishes rendering.
  2. Does the MVC framework call Dispose() on the Controller before or after the view is rendered? Or, does the MVC framework leave that up to the GarbageCollector?
6
  • 2
    I am sooo lookig forward to the answer to this one! GREAT question! Commented Sep 4, 2009 at 15:43
  • Without looking at other code (yours or ASP.NET MVC's..) why exactly do you need to null out the configManager? Does that help anything? Think thoroughly before any of you "DUH" me.. Commented Oct 11, 2010 at 14:54
  • I mean in a general case like that a race condition can easily be removed like so. In this particular case I doubt that a controller instance would be used by more than one thread and therefore there is no risk of a race condition whatsoever. Commented Oct 11, 2010 at 14:56
  • 1
    @Andrei: It's just a bit of defensive-coding. It prevents me from Disposing the Database Connection twice, if my dispose method gets called twice. Commented Oct 11, 2010 at 15:26
  • 1
    @Andrei: Well, in my opinion "Ignoring" and "Calling Dispose on Child Objects Anyways" are completely different. Hence the check. Commented Oct 11, 2010 at 21:07

2 Answers 2

71

Dispose is called after the view is rendered, always.

The view is rendered in the call to ActionResult.ExecuteResult. That's called (indirectly) by ControllerActionInvoker.InvokeAction, which is in turn called by ControllerBase.ExecuteCore.

Since the controller is in the call stack when the view is rendered, it cannot be disposed then.

Sign up to request clarification or add additional context in comments.

2 Comments

Great, do you have documentation? I just want to be sure.
Great! It'd be great to find a doc explaining it. But expanded answer was really comforting. Code is the better doc at all. :D
37

Just to expand on Craig Stuntz's Answer:

The ControllerFactory handles when a Controller is disposed. When implementing the IControllerFactory interface, one of the methods that needs to be implemented is ReleaseController.

I am not sure what ControllerFactory you are using, whether you rolled your own, but in Reflector looking at the DefaultControllerFactory, the ReleaseController method is implemented like so:

public virtual void ReleaseController(IController controller)
{
    IDisposable disposable = controller as IDisposable;
    if (disposable != null)
    {
        disposable.Dispose();
    }
}

An IController reference is passed in, if that controller implements IDisposable, then that controllers Dispose method is called. So, if you have anything you need disposing after the request is finished, which is after the view is rendered. Inherit off of IDisposable and put your logic in the Dispose method to release any resources.

The ReleaseController method is called by the System.Web.Mvc.MvcHandler which handles the request and it implements IHttpHandler. The ProcessRequest takes the HttpContext given to it and starts the process of finding the controller to handle the request, by calling into the implemented ControllerFactory. If you look in the ProcessRequest method you will see the finally block which calls the ControllerFactory's ReleaseController. This is only called when the Controller has returned a ViewResult.

2 Comments

Awesome answer. I couldn't figure out why a direct instance of a Controller object would not let me call Dispose() on it, but it looks like I need to create a new instance of it using the IDisposable interface. This worked for me!
So... HttpContext is a male? Now I am really confused.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.