web-dev-qa-db-ja.com

ASP MVC:IController Dispose()はいつ呼び出されますか?

大規模なMVCアプリの1つの大きなリファクタリング/速度調整を行っています。数か月前から実稼働環境にデプロイされており、接続プール内の接続を待機するタイムアウトが発生し始めていました。接続が適切に破棄されないまで問題を追跡しました。

それを踏まえて、ベースコントローラにこの変更を加えました。

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

今、私は2つの質問があります:

  1. 競合状態を導入していますか?configManagerは、ビューに_IQueryable<>_パラメーターを公開するDataContextを管理するため、Dispose()は、ビューがレンダリングを完了する前にコントローラーで呼び出されません。
  2. ビューがレンダリングされる前または後に、MVCフレームワークはコントローラーでDispose()を呼び出しますか?または、MVCフレームワークはそれをGarbageCollectorに任せますか?
81
John Gietzen

Disposeは、ビューがレンダリングされた後に呼び出されますalways

ビューは、ActionResult.ExecuteResultの呼び出しでレンダリングされます。これはControllerActionInvoker.InvokeActionによって(間接的に)呼び出され、ControllerBase.ExecuteCoreによって呼び出されます。

ビューがレンダリングされるとき、コントローラーは呼び出しスタック内にあるため、破棄することはできません。

68
Craig Stuntz

Craig Stuntz's Answer を展開するだけです:

ControllerFactoryは、コントローラーが破棄されたときに処理します。 IControllerFactoryインターフェイスを実装する場合、実装する必要があるメソッドの1つはReleaseControllerです。

自分がどのControllerFactoryを使用しているか、自分でロールしたかどうかはわかりませんが、DefaultControllerFactoryを見るReflectorでは、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メソッドを見ると、ControllerFactoryのReleaseControllerを呼び出すfinallyブロックが表示されます。これは、コントローラーがViewResultを返したときにのみ呼び出されます。

36
Dale Ragan