web-dev-qa-db-fra.com

ASP MVC: Quand est-ce que IController Dispose () est appelé?

Je traverse une grande refactorisation/modification de la vitesse d'une de mes plus grandes applications MVC. Il est déployé en production depuis quelques mois maintenant, et je commençais à obtenir des délais d'attente pour les connexions dans le pool de connexions. J'ai suivi le problème jusqu'à ce que les connexions ne soient pas éliminées correctement.

À la lumière de cela, j'ai depuis apporté cette modification à mon contrôleur de 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);
    }
}

Maintenant, j'ai deux questions:

  1. Suis-je en train d'introduire une condition de concurrence? Puisque le configManager gère le DataContext qui expose les paramètres IQueryable<> Aux vues, je dois m'assurer que Dispose() ne sera pas appelé sur le contrôleur avant la fin du rendu de la vue.
  2. Le framework MVC appelle-t-il Dispose() sur le Controller avant ou après le rendu de la vue? Ou, le framework MVC laisse-t-il cela au GarbageCollector?
81
John Gietzen

Dispose est appelé après le rendu de la vue, toujours.

La vue est rendue dans l'appel à ActionResult.ExecuteResult. Cela s'appelle (indirectement) par ControllerActionInvoker.InvokeAction, qui est à son tour appelé par ControllerBase.ExecuteCore.

Étant donné que le contrôleur est dans la pile d'appels lorsque la vue est rendue, elle ne peut pas être supprimée à ce moment-là.

68
Craig Stuntz

Juste pour développer Réponse de Craig Stuntz :

Le ControllerFactory gère lorsqu'un contrôleur est éliminé. Lors de l'implémentation de l'interface IControllerFactory, l'une des méthodes qui doit être implémentée est ReleaseController.

Je ne sais pas quel ControllerFactory vous utilisez, que vous ayez roulé le vôtre, mais dans Reflector en regardant DefaultControllerFactory, la méthode ReleaseController est implémentée comme suit:

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

Une référence IController est transmise, si ce contrôleur implémente IDisposable, alors la méthode Dispose des contrôleurs est appelée. Donc, si vous avez quelque chose à supprimer une fois la demande terminée, c'est-à-dire après le rendu de la vue. Héritez de IDisposable et placez votre logique dans la méthode Dispose pour libérer toutes les ressources.

La méthode ReleaseController est appelée par System.Web.Mvc.MvcHandler qui gère la demande et implémente IHttpHandler. Le ProcessRequest prend le HttpContext qui lui est donné et démarre le processus de recherche du contrôleur pour gérer la demande, en appelant le ControllerFactory implémenté. Si vous regardez dans la méthode ProcessRequest, vous verrez le bloc finally qui appelle le ReleaseController de ControllerFactory. Ceci n'est appelé que lorsque le contrôleur a renvoyé un ViewResult.

36
Dale Ragan