ASP.NET MVC: Wird der Controller für jede Anforderung erstellt?

112

Sehr einfache Frage: Werden Controller in ASP.NET für jede HTTP-Anforderung erstellt oder werden sie beim Start der Anwendung erstellt und bei allen Anforderungen wiederverwendet?

Wird der Controller nur für eine bestimmte HTTP-Anforderung erstellt?

Kann ich mich darauf verlassen, wenn meine vorherigen Annahmen korrekt sind? Ich möchte einen Datenbankkontext (Entity Framework) erstellen, der nur für eine Anforderung verwendet wird. Wenn ich es als eine im Konstruktor des Controllers initialisierte Eigenschaft erstelle, wird dann gewährt, dass für jede Anforderung eine neue Kontextinstanz erstellt wird?

Rasto
quelle
16
Setzen Sie einen Haltepunkt in Ihren Konstruktor und sehen Sie, was Sie herausfinden können ...
Greg B
10
@ Greg B: tolle Idee, außer es wird mir nicht sagen, ob es sich immer so verhält - wenn sich die Umstände ändern und ein Controller sein Verhalten ändert, habe ich einen Fehler, der wirklich schwer zu finden sein könnte ...
Rasto
@drasto wie wirst du überprüfen, ob es immer so funktioniert? Überprüfen Sie jede Anfrage an Ihre Bewerbung?
Greg B
4
@Todd Smith bitte einen Link oder zumindest einen vollständigen Namen. Baumbuchstaben IoC sind schwer zu googeln. Danke dir.
Rasto
2
@drasto IoC = Umkehrung der Kontrolle en.wikipedia.org/wiki/Inversion_of_control
Bala R

Antworten:

103

Für jede Anforderung wird ein Controller erstellt ControllerFactory(der standardmäßig der ist DefaultControllerFactory).

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

Beachten Sie, dass der Html.ActionHTML-Helper einen anderen Controller erstellt.

Die Kurzversion ControllerActivator.Createwird aufgerufen (für jede Anforderung), um einen Controller zu erstellen (der einen neuen Controller entweder über den DependencyResolver oder über den Activator einleitet, wenn kein Resolver eingerichtet wurde):

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

Die längere Version ist folgende (Hier ist der Code aus der Quelle des 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));
    }
}

Hier ist der Controller-Werkscode:

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

Was im Grunde so heißt:

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

Welche ruft diese Methode in der ControllerActivator(Dieser Code versucht, den DependencyResolver nach einer Instanz zu fragen, oder verwendet nur die Activator-Klasse):

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

Dies könnte unter zu viele Informationen fallen ... Aber ich wollte zeigen, dass Sie wirklich für JEDE Anfrage einen neuen Controller bekommen.

Linkgoron
quelle
@ Daniel @ drasto hier ist das Zitat aspnet.codeplex.com/SourceControl/changeset/view/63930#266503
Bala R
32

Ich habe einen leeren Konstruktor für einen Controller erstellt und einen Haltepunkt in den Konstruktor eingefügt. Es wurde jedes Mal getroffen, wenn es eine neue Anfrage gab. Ich denke, es ist für jede Anfrage erstellt.

Bala R.
quelle
3
+1 Ich hoffe, Sie haben Recht, aber ich hätte gerne ein besseres Wissen als nur "in allen Fällen, in denen ich versucht habe, dass es funktioniert". Wenn es manchmal aus irgendeinem Grund nicht so funktioniert, bedeutet es einen Fehler.
Rasto
6
@ Drasto: Kein Grund zur Sorge. Der Controller wird für jede Anforderung instanziiert. Ein Teil des Speichers wird zwar wiederverwendet, aber Sie sollten sich keine Gedanken über den Controller-Status machen (falls Sie einen haben). Es wird wie erwartet initialisiert. Es kann jedoch vorkommen, dass mehr als ein Controller instanziiert wird. Und dann rufen Ansichten Controller-Aktionen auf (dh Html.RenderAction("action", "controller");)
Robert Koritnik
@ RobertKoritnik & Bala R, ich habe bitte eine Frage. Was passiert mit den Objekten, die wie Student oder List <Student> erstellt wurden, nachdem die Aktionsmethode sie oder sie der Ansicht bereitgestellt hat? Werden sie entsorgt? Und was passiert für diese Objekte, wenn eine neue Anfrage kommt?
Mahdi Alkhatib
3

Der Controller wird erstellt, wenn eine Aktion in einem bestimmten Controller ausgeführt wird.

Ich habe ein Projekt, in dem alle meine Controller von einem erben, ApplicationControllerund jedes Mal, wenn eine Aktion ausgeführt wird, wird der Haltepunkt innerhalb des ApplicationController- unabhängig von seinem " aktuellen " Controller erreicht.

Ich initialisiere meinen Agenten (der als mein Kontext fungiert), wenn mein Controller wie folgt erstellt wird:

    public IWidgetAgent widgetAgent { get; set; }

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

    }

Dies ist offensichtlich nicht das, was Sie brauchen - wie Sie erwähnt haben, wollten Sie bei jedem Aufruf nur eine einzige Instanz. Es ist jedoch ein guter Ort, um zu überprüfen, was jedes Mal vor sich geht, und um sicherzustellen, dass derzeit keine andere Instanz Ihres Kontexts vorhanden ist.

Hoffe das hilft.

Rion Williams
quelle
2

Controller werden für jede Anforderung erstellt. Die Magie geschieht im Routing in der Datei gobal.aspx. Die Zuordnungspfade leiten MVC an die zu erstellende Steuerung und die Aktion auf der aufzurufenden Steuerung sowie die an sie zu übergebenden Parameter.

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

BlackICE
quelle
Zitierweise erforderlich - unterstützende Informationen können nicht im verknüpften Dokument gefunden werden. Vielen Dank
Rasto