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


83

大きな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管理しDataContextている公開されるIQueryable<>ビューのパラメータを、私はそれを確認する必要がありDispose()ビューが終了すると、レンダリング前にコントローラーで呼び出されることはありません。
  2. MVCフレームワークDispose()は、ビューがレンダリングされる前または後にコントローラーを呼び出しますか?または、MVCフレームワークはそれをGarbageCollectorに任せていますか?

2
私はこれに対する答えをとても楽しみにしています!素晴らしい質問です!
ダニエルエリオット

他のコード(自分のコードまたはASP.NET MVCのコード)を見ずに、なぜconfigManagerを正確に無効にする必要があるのですか?それは何か助けになりますか?私を「
DUH

つまり、そのような一般的なケースでは、競合状態はそのように簡単に取り除くことができます。この特定のケースでは、コントローラーインスタンスが複数のスレッドによって使用されることは疑わしいため、競合状態のリスクはまったくありません。
アンドレイRînea

1
@Andrei:それはほんの少しの防御的なコーディングです。disposeメソッドが2回呼び出された場合、データベース接続を2回破棄できなくなります。
John Gietzen 2010年

1
@Andrei:そうですね、私の意見では、「無視する」と「とにかく子オブジェクトでDisposeを呼び出す」は完全に異なります。したがって、チェック。
John Gietzen 2010年

回答:


70

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

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

ビューがレンダリングされるとき、コントローラーはコールスタックにあるため、その時点で破棄することはできません。


すばらしい、ドキュメントはありますか?確認したいだけです。
John Gietzen 2009

すごい!それを説明しているドキュメントを見つけるのは素晴らしいことです。しかし、拡張された答えは本当に慰めでした。コードはまったく優れたドキュメントです。:D
CSA

37

Craig Stuntzの回答を拡張するだけです:

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を返したときにのみ呼び出されます。


素晴らしい答え。Controllerオブジェクトの直接インスタンスでDispose()を呼び出せない理由がわかりませんでしたが、IDisposableインターフェイスを使用して新しいインスタンスを作成する必要があるようです。これは私のために働いた!
メガマット2012

それで...HttpContext男性ですか?今、私は本当に混乱しています。
chef_Code 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.