ASP MVC:何时调用IController Dispose()?


83

我正在对其中一个较大的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);
    }
}

现在,我有两个问题:

  1. 我要介绍比赛条件吗?由于configManager管理DataContext暴露IQueryable<>参数给视图的,因此我需要确保Dispose()在视图完成渲染之前不会在控制器上调用该参数。
  2. MVC框架Dispose()是在呈现视图之前还是之后在Controller上调用的?还是MVC框架将其留给GarbageCollector?

2
我很期待这个答案!伟大的问题!
Daniel Elliott

在不查看其他代码(您的代码或ASP.NET MVC的代码。)的情况下,为什么您确实需要清空configManager?这有什么帮助吗?之前,任何的你“DUH”我彻底想..
安德烈Rînea

我的意思是,在一般情况下,这样的比赛条件可以轻松消除。在这种特殊情况下,我怀疑一个以上的线程将使用一个控制器实例,因此不存在出现竞争状况的风险。
AndreiRînea'10

1
@Andrei:只是一些防御性编码。如果我的dispose方法被调用了两次,它将阻止我两次处置数据库连接。
John Gietzen

1
@Andrei:好吧,在我看来,“忽略”和“无论如何都对子对象调用处置”是完全不同的。因此检查。
John Gietzen

Answers:


70

渲染视图后,始终调用Dispose 。

该视图在对的调用中呈现ActionResult.ExecuteResult。被(间接)ControllerActionInvoker.InvokeAction称为,又被称为ControllerBase.ExecuteCore

由于呈现视图时控制器位于调用堆栈中,因此无法将其处置。


太好了,您有文件吗?我只想确定。
John Gietzen

大!很高兴找到一个解释它的医生。但是,扩大答案确实令人感到安慰。代码是更好的文档。:D
CSA

37

只是为了扩大Craig Stuntz的答案

当处置Controller时,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方法中以释放所有资源。

System.Web.Mvc.MvcHandler调用ReleaseController方法,该方法处理请求并实现IHttpHandler。通过调用实现的ControllerFactory,ProcessRequest接受赋予它的HttpContext并开始查找控制器以处理请求的过程。如果查看ProcessRequest方法,将看到finally块,该块调用ControllerFactory的ReleaseController。仅当Controller返回ViewResult时才调用此方法。


很棒的答案。我不知道为什么控制器对象的直接实例不能让我在其上调用Dispose(),但是看起来我需要使用IDisposable接口创建它的新实例。这对我有用!
MegaMatt 2012年

所以...HttpContext是男性吗?现在我真的很困惑。
Chef_Code
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.