2009-09-04 6 views
71

Przechodzę przez duży usprawnienia/dostosowania prędkości jednej z moich większych aplikacji MVC. Został wdrożony do produkcji od kilku miesięcy i zaczynałem otrzymywać limity czasu oczekujące na połączenia w puli połączeń. Zidentyfikowaliśmy problem, aby połączenia nie zostały odpowiednio usunięte.ASP MVC: Kiedy wywoływana jest funkcja IController Dispose()?

W świetle tego, mam od dokonaniu tej zmiany do mojego kontrolera Base:

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

Teraz mam dwa pytania:

  1. jestem wprowadzające stan wyścigu? Od configManager zarządza DataContext, który udostępnia parametry IQueryable<> do widoków, muszę się upewnić, że Dispose() nie zostanie wywołany na kontroler przed zakończeniem renderowania widoku.
  2. Czy środowisko MVC wywołuje Dispose() na kontrolerze przed lub po wyświetleniu widoku? A może ramy MVC pozostawiają ten obiekt w GarbageCollector?
+1

Jestem bardzo zadowolony z odpowiedzi na to pytanie! WIELKIE pytanie! –

+0

Bez patrzenia na inny kod (twój lub ASP.NET MVC ..), dlaczego dokładnie trzeba zerwać configManager? Czy to coś pomoże? Pomyśl dokładnie zanim ktokolwiek z was "DUH" mnie .. –

+0

Mam na myśli, że w tak ogólnym przypadku warunki wyścigu mogą być łatwo usunięte, jak to się dzieje. W tym konkretnym przypadku wątpię, aby instancja kontrolera była używana przez więcej niż jeden wątek i dlatego nie ma ryzyka jakiegokolwiek stanu wyścigu. –

Odpowiedz

60

utylizować nazywa po widok jest renderowany, zawsze.

Widok jest renderowany w połączeniu z numerem ActionResult.ExecuteResult. To się nazywa (pośrednio) przez ControllerActionInvoker.InvokeAction, która z kolei jest wywoływana przez ControllerBase.ExecuteCore.

Ponieważ kontroler znajduje się na stosie wywołań, gdy widok jest renderowany, nie można go wówczas usunąć.

+0

Dobrze, masz dokumentację? Chcę tylko mieć pewność. –

+0

Dokumentacja to kod źródłowy MVC. Zobacz rozszerzoną odpowiedź. –

+0

Idealny. Dziękuję Ci! –

32

Wystarczy rozwinąć Craig Stuntz's Answer:

ControllerFactory uchwyty, gdy kontroler jest umieszczony. Podczas implementowania interfejsu IControllerFactory, jedną z metod, które muszą zostać zaimplementowane, jest ReleaseController.

Nie jestem pewien, co ControllerFactory używasz, czy walcowane własną rękę, ale w reflektor patrząc na DefaultControllerFactory metoda ReleaseController jest realizowany tak:

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

IController odniesienia jest przekazywana, jeśli ten kontroler implementuje IDisposable, wówczas wywoływana jest ta metoda Controlers Dispose. Tak więc, jeśli masz coś, czego potrzebujesz, pozbywając się po zakończeniu żądania, czyli po renderowaniu widoku. Odziedzicz IDisposable i umieść logikę w metodzie Dispose, aby zwolnić zasoby.

Metoda ReleaseController jest wywoływana przez System.Web.Mvc.MvcHandler, który obsługuje żądanie i implementuje IHttpHandler. ProcessRequest pobiera podany HttpContext i rozpoczyna proces znajdowania kontrolera, aby obsłużyć żądanie, poprzez wywołanie do zaimplementowanego ControllerFactory. Jeśli spojrzysz na metodę ProcessRequest, zobaczysz blok finally, który wywołuje narzędzie ReleaseController ControllerFactory. Jest to wywoływane tylko wtedy, gdy kontroler zwrócił wartość ViewResult.

+0

Niesamowita odpowiedź. Nie mogłem się domyślić, dlaczego bezpośrednia instancja obiektu kontrolera nie pozwala mi wywołać metody Dispose(), ale wygląda na to, że muszę utworzyć nową instancję za pomocą interfejsu IDisposable. To działało dla mnie! –

+0

Więc ... 'HttpContext' jest mężczyzną? Teraz jestem naprawdę zdezorientowany. –