140 votes

ASP.NET MVC : Le contrôleur est-il créé pour chaque demande ?

Question très simple : Les contrôleurs en ASP.NET sont-ils créés pour chaque requête HTTP, ou sont-ils créés au démarrage de l'application et réutilisés au fil des requêtes ?

Le contrôleur sera-t-il créé uniquement pour une requête HTTP particulière ?

Si mes hypothèses précédentes sont correctes, puis-je m'y fier ? Je veux créer un contexte de base de données (Entity Framework) qui ne vivra que pour une seule requête. Si je le crée comme une propriété initialisée dans le constructeur du contrôleur, est-il garanti qu'une nouvelle instance du contexte sera créée pour chaque requête ?

120voto

Linkgoron Points 3060

Un contrôleur est créé pour chaque demande par le ControllerFactory (qui par défaut est le DefaultControllerFactory ).

http://msdn.microsoft.com/en-us/library/system.web.mvc.defaultcontrollerfactory.aspx

Notez que le Html.Action Html Helper va créer un autre contrôleur.

La version courte est que ControllerActivator.Create est appelé (pour chaque requête) pour créer un contrôleur (qui injecte un nouveau contrôleur soit par le DependencyResolver, soit par l'Activator si aucun Resolver n'a été mis en place) :

public IController Create(RequestContext requestContext, Type controllerType) 
{
    try 
    {
        return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
    }

La version longue est la suivante (voici le code de la source du MvcHandler) :

protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
    SecurityUtil.ProcessInApplicationTrust(() =>
    {
        IController controller;
        IControllerFactory factory;
        ProcessRequestInit(httpContext, out controller, out factory);

        try
        {
            controller.Execute(RequestContext);
        }
        finally
        {
            factory.ReleaseController(controller);
        }
    });
}

private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
    // non-relevant code
    // Instantiate the controller and call Execute
    factory = ControllerBuilder.GetControllerFactory();
    controller = factory.CreateController(RequestContext, controllerName);
    if (controller == null)
    {
        throw new InvalidOperationException(
            String.Format(
                CultureInfo.CurrentCulture,
                MvcResources.ControllerBuilder_FactoryReturnedNull,
                factory.GetType(),
                controllerName));
    }
}

Voici le code d'usine du contrôleur :

public virtual IController CreateController(RequestContext requestContext, string controllerName) 
{
    Type controllerType = GetControllerType(requestContext, controllerName);
    IController controller = GetControllerInstance(requestContext, controllerType);
    return controller;
}

Ce qui revient à dire que :

protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType) 
{
    return ControllerActivator.Create(requestContext, controllerType);
}

qui appelle cette méthode dans le ControllerActivator (Ce code essaie de demander une instance au DependencyResolver, ou utilise simplement la classe Activator) :

public IController Create(RequestContext requestContext, Type controllerType) 
{
    try 
    {
        return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
    }

Cela pourrait tomber sous le coup de trop d'informations... Mais je voulais montrer que vous obtenez vraiment un nouveau contrôleur pour CHAQUE demande.

39voto

Bala R Points 57552

J'ai créé un constructeur vide pour un contrôleur et j'ai placé un point d'arrêt dans le constructeur. Il a été atteint chaque fois qu'il y avait une nouvelle demande. Donc je pense qu'il est créé pour chaque requête.

3voto

Rion Williams Points 22784

Le contrôleur sera créé lorsqu'une action dans un contrôleur spécifique est exécutée.

J'ai un projet où tous mes contrôleurs héritent d'un ApplicationController et chaque fois qu'une action est exécutée, le point d'arrêt est atteint à l'intérieur de l'objet ApplicationController - indépendamment de son " actual " Contrôleur.

J'initialise mon agent (qui fonctionne comme mon contexte) chaque fois que mon contrôleur est créé comme tel :

    public IWidgetAgent widgetAgent { get; set; }

    public WidgetController()
    {
        if (widgetAgent == null)
        {
            widgetAgent = new WidgetAgent();
        }

    }

Ce n'est évidemment pas ce dont vous avez besoin - puisque vous avez mentionné que vous ne vouliez qu'une seule instance à chaque fois qu'elle était appelée. Mais c'est un bon endroit pour vérifier ce qui se passe à chaque fois et pour s'assurer qu'une autre instance de votre contexte n'existe pas actuellement.

J'espère que cela vous aidera.

2voto

BlackICE Points 4561

Les contrôleurs sont créés pour chaque demande. La magie se produit dans le routage dans le gobal.aspx. Les chemins de mappage indiquent à MVC le contrôleur à créer, l'action à appeler sur le contrôleur et les paramètres à lui passer.

http://www.asp.net/mvc/tutorials/asp-net-mvc-routing-overview-vb

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X