ASP MVC: Когда вызывается IController Dispose()?

Я перехожу к большому рефакторингу/настройке скорости одного из моих более крупных приложений MVC. Он был развернут на производство в течение нескольких месяцев, и я начал получать тайм-ауты, ожидая подключения в пуле соединений. Я отследил проблему до того, что соединения не были правильно настроены.

В свете этого я с тех пор внес это изменение в свой базовый контроллер:

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);
    }
}

Теперь у меня есть два вопроса:

  • Я представляю условие гонки? Поскольку configManager управляет DataContext, который предоставляет параметры IQueryable<> для взгляды, мне нужно убедиться, что Dispose() не будет вызываться на контроллере до того, как представление закончит рендеринг.
  • Является ли MVC-инфраструктура вызовом Dispose() на контроллере до или после отображения представления? Или же структура MVC оставляет это до GarbageCollector?

Ответ 1

Dispose вызывается после визуализации представления, всегда.

Вид отображается при вызове ActionResult.ExecuteResult. Это называется (косвенно) на ControllerActionInvoker.InvokeAction, которое, в свою очередь, называется ControllerBase.ExecuteCore.

Так как контроллер находится в стеке вызовов, когда визуализируется представление, он не может быть удален тогда.

Ответ 2

Просто чтобы развернуть ответ Крэйга Штутца:

ControllerFactory обрабатывает, когда контроллер установлен. При реализации интерфейса IControllerFactory одним из методов, который должен быть реализован, является ReleaseController.

Я не уверен, что вы используете ControllerFactory, независимо от того, катите ли вы свой собственный, но в Reflector, смотрящем на DefaultControllerFactory, метод ReleaseController реализован следующим образом:

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

Ссылка на IController передается, если этот контроллер реализует IDisposable, тогда вызывается этот метод Dispose. Таким образом, если у вас есть что-то, что вам нужно удалить после завершения запроса, то есть после визуализации представления. Наследуйте IDisposable и поместите свою логику в метод Dispose для освобождения любых ресурсов.

Метод ReleaseController вызывается System.Web.Mvc.MvcHandler, который обрабатывает запрос и реализует IHttpHandler. ProcessRequest передает HttpContext, заданный ему, и запускает процесс поиска контроллера для обработки запроса, вызывая в реализованный ControllerFactory. Если вы посмотрите в методе ProcessRequest, вы увидите блок finally, который вызывает ControllerFactory ReleaseController. Это вызывается только тогда, когда контроллер вернул ViewResult.