2009-09-04 25 views
71

Estoy pasando por un gran cambio de refactorización/velocidad de una de mis aplicaciones MVC más grandes. Se ha implementado en la producción durante unos meses y estaba empezando a tener tiempos de espera esperando conexiones en el grupo de conexiones. He rastreado el problema hasta que las conexiones no se eliminan adecuadamente.ASP MVC: ¿Cuándo se llama IController Dispose()?

En vista de ello, desde entonces he hecho este cambio a mi 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); 
    } 
} 

Ahora, tengo dos preguntas:

  1. ¿Estoy introducción de una condición de carrera? Desde el configManager gestiona el DataContext que expone IQueryable<> parámetros a los puntos de vista, que necesita para asegurarse de que Dispose() no se llamará en el controlador antes de la vista termina de renderizado.
  2. ¿La estructura MVC llama al Dispose() en el controlador antes o después de que se visualice la vista? O bien, ¿el marco de MVC deja ese hasta el GarbageCollector?
+1

¡Estoy esperando la respuesta a este! ¡GRAN pregunta! –

+0

Sin mirar otro código (el tuyo o ASP.NET MVC ...) ¿por qué necesitas anular el configManager? ¿Eso ayuda a algo? Piensa bien antes de que alguno de ustedes "DUH" me ... –

+0

Quiero decir en un caso general como que una condición de carrera puede eliminarse fácilmente como tal. En este caso particular, dudo que una instancia de controlador sea utilizada por más de un hilo y, por lo tanto, no hay riesgo de una condición de carrera en absoluto. –

Respuesta

60

Desechar se llama después de la vista se vuelve, siempre .

La vista se representa en la llamada al ActionResult.ExecuteResult. Eso se llama (indirectamente) por ControllerActionInvoker.InvokeAction, que a su vez se llama por ControllerBase.ExecuteCore.

Como el controlador está en la pila de llamadas cuando se muestra la vista, no se puede eliminar.

+0

Genial, ¿tienes documentación? Solo quiero estar seguro. –

+0

La documentación es el código fuente de MVC. Ver respuesta expandida. –

+0

Perfecto. ¡Gracias! –

32

Sólo para ampliar Craig Stuntz's Answer:

El ControllerFactory maneja cuando se dispone de un controlador. Al implementar la interfaz IControllerFactory, uno de los métodos que necesita implementarse es ReleaseController.

no estoy seguro de lo que ControllerFactory que está utilizando, si usted rodó su cuenta, pero en el reflector mirando el DefaultControllerFactory, el método ReleaseController se lleva a cabo de esta manera:

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

Un IController se pasa, si ese controlador implementa IDisposable, entonces se llama al método Dispose de los controladores. Por lo tanto, si tiene algo que necesita eliminar después de que la solicitud finalice, que es después de que se visualice la vista. Heredar de IDisposable y poner su lógica en el método Dispose para liberar cualquier recurso.

El método Release.Cont.Mvc.Mvc llama al método ReleaseController que maneja la solicitud e implementa IHttpHandler. El ProcessRequest toma el HttpContext dado a él y comienza el proceso de encontrar el controlador para manejar la solicitud, llamando al ControllerFactory implementado. Si observa el método ProcessRequest, verá el bloque finally que llama al ReleaseController de ControllerFactory. Esto solo se llama cuando el Controlador ha devuelto ViewResult.

+0

Respuesta impresionante. No pude entender por qué una instancia directa de un objeto Controller no me permitía llamar a Dispose() en él, pero parece que necesito crear una nueva instancia usando la interfaz IDisposable. ¡Esto funcionó para mí! –

+0

Entonces ... 'HttpContext' es un hombre? Ahora estoy realmente confundido. –

Cuestiones relacionadas