Przechodzę przez dużą refaktoryzację / poprawianie szybkości jednej z moich większych aplikacji MVC. Został wdrożony do produkcji od kilku miesięcy i zacząłem otrzymywać limity czasu oczekiwania na połączenia w puli połączeń. Wyśledziłem problem do nieprawidłowego usunięcia połączeń.
W związku z tym dokonałem tej zmiany w moim kontrolerze podstawowym:
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:
- Czy wprowadzam warunek wyścigu? Ponieważ
configManager
zarządza,DataContext
który udostępniaIQueryable<>
parametry widokom , muszę się upewnić, żeDispose()
nie zostanie wywołany na kontrolerze przed zakończeniem renderowania widoku. - Czy struktura MVC wywołuje
Dispose()
kontroler przed lub po renderowaniu widoku? A może struktura MVC pozostawia to GarbageCollector?
asp.net-mvc
linq-to-sql
garbage-collection
idisposable
John Gietzen
źródło
źródło
Odpowiedzi:
Dispose jest wywoływana po wyrenderowaniu widoku, zawsze .
Widok jest renderowany w wywołaniu
ActionResult.ExecuteResult
. Nazywa się to (pośrednio) przezControllerActionInvoker.InvokeAction
, które z kolei jest wywoływane przezControllerBase.ExecuteCore
.Ponieważ kontroler znajduje się na stosie wywołań, gdy widok jest renderowany, nie można go usunąć.
źródło
Aby rozwinąć odpowiedź Craiga Stuntza :
ControllerFactory obsługuje, gdy kontroler zostanie usunięty. Podczas implementowania interfejsu IControllerFactory jedną z metod, które należy zaimplementować, jest ReleaseController.
Nie jestem pewien, jakiego ControllerFactory używasz, czy wywaliłeś swój własny, ale w Reflektorze patrząc na DefaultControllerFactory, metoda ReleaseController jest zaimplementowana w następujący sposób:
public virtual void ReleaseController(IController controller) { IDisposable disposable = controller as IDisposable; if (disposable != null) { disposable.Dispose(); } }
Odwołanie do IController jest przekazywane, jeśli ten kontroler implementuje IDisposable, wywoływana jest metoda Dispose kontrolerów. Tak więc, jeśli masz cokolwiek, czego potrzebujesz, po zakończeniu żądania, czyli po wyrenderowaniu widoku. Dziedzicz IDisposable i umieść logikę w metodzie Dispose, aby zwolnić wszystkie zasoby.
Metoda ReleaseController jest wywoływana przez System.Web.Mvc.MvcHandler, który obsługuje żądanie i implementuje IHttpHandler. ProcessRequest pobiera otrzymany HttpContext i rozpoczyna proces znajdowania kontrolera do obsługi żądania, wywołując zaimplementowaną ControllerFactory. Jeśli spojrzysz na metodę ProcessRequest, zobaczysz ostatni blok, który wywołuje ReleaseController ControllerFactory. Jest to wywoływane tylko wtedy, gdy kontroler zwrócił ViewResult.
źródło
HttpContext
jest mężczyzną? Teraz jestem naprawdę zdezorientowany.