2009-09-04 16 views
71

Sto passando attraverso un grande refactoring/velocizzazione di una delle mie applicazioni MVC più grandi. È stato distribuito in produzione per alcuni mesi e stavo iniziando a ottenere timeout in attesa di connessioni nel pool di connessioni. Ho rintracciato il problema fino a quando le connessioni non vengono smaltite correttamente.ASP MVC: quando viene chiamato IController Dispose()?

Alla luce di questo, allora ho fatto questo cambiamento al mio controller di 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); 
    } 
} 

Ora, ho due domande:

  1. Perchè sono l'introduzione di una condizione di competizione? Dal momento che il configManager gestisce il DataContext che espone IQueryable<> parametri i punti di vista, ho bisogno di fare in modo che Dispose() non sarà chiamato sul controller prima che la vista finisce di rendering.
  2. Il framework MVC chiama Dispose() sul controller prima o dopo il rendering della visualizzazione? Oppure, il framework MVC lascia quello fino a GarbageCollector?
+1

Sono così bello guardare avanti per la risposta a questo! GRANDE domanda! –

+0

Senza guardare altro codice (tuo o ASP.NET MVC ..) perché esattamente hai bisogno di annullare il configManager? Questo aiuta qualcosa? Pensa bene prima che qualcuno di voi "DUH" me .. –

+0

Intendo in un caso generale come quello, una condizione di competizione può essere facilmente rimossa in questo modo. In questo caso specifico dubito che un'istanza del controllore possa essere utilizzata da più di un thread e quindi non vi è alcun rischio di una condizione di competizione di sorta. –

risposta

60

Dispose viene richiamato dopo la vista è reso, sempre.

La vista viene visualizzata nella chiamata a ActionResult.ExecuteResult. Questo viene chiamato (indirettamente) da ControllerActionInvoker.InvokeAction, che a sua volta viene chiamato da ControllerBase.ExecuteCore.

Poiché il controller si trova nello stack di chiamate quando viene eseguito il rendering della vista, non può essere eliminato.

+0

Ottimo, hai documentazione? Voglio solo essere sicuro. –

+0

La documentazione è il codice sorgente MVC. Vedi la risposta estesa. –

+0

Perfetto. Grazie! –

32

Giusto per espandere il Craig Stuntz's Answer:

Il ControllerFactory maniglie quando un controller è disposto. Quando si implementa l'interfaccia IControllerFactory, uno dei metodi che deve essere implementato è ReleaseController.

io non sono sicuro di quello che ControllerFactory che si sta utilizzando, se si laminati da soli, ma in Reflector guardando il DefaultControllerFactory, il metodo ReleaseController è implementato in questo modo: è passato in

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

Un IController di riferimento, se quel controller implementa IDisposable, allora viene chiamato quel metodo Dispose di controller. Quindi, se hai qualcosa da smaltire dopo il completamento della richiesta, che è dopo che la vista è stata renderizzata. Eredita da IDisposable e inserisci la tua logica nel metodo Dispose per rilasciare qualsiasi risorsa.

Il metodo ReleaseController viene chiamato da System.Web.Mvc.MvcHandler che gestisce la richiesta e implementa IHttpHandler. Il ProcessRequest prende il HttpContext dato ad esso e avvia il processo di trovare il controller per gestire la richiesta, chiamando il ControllerFactory implementato. Se si guarda nel metodo ProcessRequest, verrà visualizzato il blocco finally che chiama ReleaseController di ControllerFactory. Questo viene chiamato solo quando il Controller ha restituito un ViewResult.

+0

Risposta straordinaria. Non riuscivo a capire perché un'istanza diretta di un oggetto Controller non mi permettesse di chiamare Dispose() su di esso, ma sembra che abbia bisogno di crearne una nuova usando l'interfaccia IDisposable. Questo ha funzionato per me! –

+0

Quindi ... 'HttpContext' è un maschio? Ora sono davvero confuso. –

Problemi correlati