ASP.NET MVC: il controller viene creato per ogni richiesta?


112

Domanda molto semplice: i controller in ASP.NET vengono creati per ogni richiesta HTTP o vengono creati all'avvio dell'applicazione e riutilizzati durante le richieste?

Il controller verrà creato solo per una particolare richiesta HTTP?

Se le mie precedenti ipotesi sono corrette, posso dipendere da esso? Voglio creare un contesto di database (Entity Framework) che vivrà solo per una richiesta. Se lo creo come una proprietà inizializzata nel costruttore del controller, è garantito che verrà creata una nuova istanza di contesto per ogni richiesta?


16
Metti un punto di interruzione nel tuo costruttore e guarda cosa riesci a scoprire ...
Greg B

10
@ Greg B: ottima idea tranne che non mi dirà se si comporta sempre così - se le circostanze cambiano e qualche controller cambia il suo comportamento ho un bug che potrebbe essere davvero difficile da trovare ...
Rasto

@drasto come farai a verificare se funziona sempre così? Controlla ogni richiesta alla tua applicazione?
Greg B

4
@Todd Smith per favore qualche link o almeno il nome completo. Le lettere dell'albero IoC sono difficili da google. Grazie.
Rasto

2
@drasto IoC = Inversion of control en.wikipedia.org/wiki/Inversion_of_control
Bala R

Risposte:


103

Viene creato un controller per ogni richiesta da parte di ControllerFactory(che per impostazione predefinita è DefaultControllerFactory).

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

Nota che l' Html.ActionHtml Helper creerà un altro controller.

La versione breve è quella ControllerActivator.Createchiamata (per ogni richiesta) per creare un Controller (che inits un nuovo Controller o tramite il DependencyResolver o tramite l'Attivatore se non è stato impostato alcun Resolver):

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

La versione più lunga è questa (ecco il codice dalla fonte da 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));
    }
}

Ecco il codice di fabbrica del controller:

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

Che fondamentalmente chiama questo:

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

Che chiama questo metodo nel ControllerActivator(Questo codice prova a chiedere a DependencyResolver un'istanza, o usa semplicemente la classe Activator):

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

Questo potrebbe cadere sotto troppe informazioni ... Ma volevo dimostrare che hai davvero un nuovo controller per OGNI richiesta.



32

Ho creato un costruttore vuoto per un controller e ho inserito un punto di interruzione nel costruttore. È stato raggiunto ogni volta che c'era una nuova richiesta. Quindi penso che sia creato per ogni richiesta.


3
+1 Spero che tu abbia ragione, ma vorrei una conoscenza approvata migliore del semplice "in tutti i casi che ho provato ha funzionato". Se a volte non funziona così per qualche motivo significa un bug.
Rasto

6
@drasto: non c'è bisogno di preoccuparsi. Il controller viene istanziato per ogni richiesta. Tuttavia, una parte della memoria viene riutilizzata, ma non dovresti preoccuparti dello stato del controller (se il tuo ne ha uno). Verrà inizializzato come previsto. Ma può esserci una situazione in cui più di un controller verrà istanziato. Ed è allora che le visualizzazioni chiamano le azioni del controller (es. Html.RenderAction("action", "controller");)
Robert Koritnik

@RobertKoritnik e Bala R, ho una domanda per favore. Cosa succede per gli oggetti creati come Studente o Elenco <Studente> dopo che il metodo di azione lo ha fornito o loro alla vista? Vengono eliminati? E cosa succede per questi oggetti quando arriva una nuova richiesta?
Mahdi Alkhatib

3

Il controller verrà creato quando viene eseguita qualsiasi azione in un controller specifico.

Ho un progetto in cui tutti i miei controller ereditano da un ApplicationControllere ogni volta che viene eseguita un'azione, il punto di interruzione viene raggiunto all'interno del controller ApplicationController, indipendentemente dal controller " corrente ".

Inizializzo il mio agente (che funziona come il mio contesto) ogni volta che il mio controller viene creato in questo modo:

    public IWidgetAgent widgetAgent { get; set; }

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

    }

Questo ovviamente non è ciò di cui hai bisogno, come hai detto che volevi solo una singola istanza ogni volta che veniva chiamato. Ma è un buon posto per controllare ogni volta cosa sta succedendo e per assicurarsi che un'altra istanza del tuo contesto non esista attualmente.

Spero che questo ti aiuti.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.