Sitzung null in ASP.Net MVC Controller-Konstruktoren

88

Warum ist Session in den Konstruktoren von Controllern null? Der Zugriff erfolgt über Aktionsmethoden. Da das MVC-Routing-Framework für die Neuerstellung eines Controllers verantwortlich ist, hat es die Sitzung zu diesem Zeitpunkt vermutlich noch nicht (erneut) instanziiert.

Weiß jemand, ob dies beabsichtigt ist und wenn ja, warum?

[Ich habe es geschafft, das Problem mithilfe eines Lazy Loading Pattern zu umgehen.]

Chris Arnold
quelle

Antworten:

78

Andrei hat Recht - es ist null, da bei Ausführung unter dem ASP.NET MVC-Framework der HttpContext (und damit HttpContext.Session) nicht festgelegt wird, wenn die Controller-Klasse wie erwartet erstellt wird, sondern später festgelegt ("injiziert") von der ControllerBuilder-Klasse. Wenn Sie den Lebenszyklus besser verstehen möchten, können Sie entweder das ASP.NET MVC-Framework herunterladen (die Quelle ist verfügbar) oder auf folgende Seite verweisen

Wenn Sie auf die Sitzung zugreifen müssen, besteht eine Möglichkeit darin, die Methode "OnActionExecuting" zu überschreiben und dort darauf zuzugreifen, da sie zu diesem Zeitpunkt verfügbar sein wird.

Wie Andrei jedoch vorschlägt, kann es möglicherweise schwierig sein, Komponententests zu schreiben, wenn Ihr Code von der Sitzung abhängt. Vielleicht können Sie die Sitzung in eine Hilfsklasse einbinden, die dann gegen eine andere, nicht austauschende Klasse ausgetauscht werden kann Web-Version, wenn Sie unter Unit-Tests ausgeführt werden. Koppeln Sie daher Ihren Controller vom Web.

Andrew W.
quelle
2
Ich bin mir nicht sicher, ob dies die richtige Aussage zu HttpContext ist. Es wurde tatsächlich direkt zu Beginn des gesamten Flusses erstellt. Sie können hier ein wenig über den detaillierten Ablauf lesen. Beletsky.net/2011/06/inside-aspnet-mvc-route-to-mvchanlder.html oder Sie können den Reflektor verwenden und sich selbst finden, wenn httpContext instanziiert wurde - es ist ungefähr Zeile 1556 in httpruntime .cs.
Alexey Shcherbak
@AlexeyShcherbak Möglicherweise ist es bereits erstellt. Bei OP geht es darum, ob es für die Sitzungseigenschaft des MVC-Controllers festgelegt wurde. dh öffentliche HttpSessionStateBase-Sitzung {get; } on System.Web.Mvc.Controller Dies sind verschiedene Dinge.
MemeDeveloper
61

Zusätzlich zu den anderen Antworten hier Controller.Sessionkönnen Sie auf die Sitzung zugreifen , obwohl sie nicht im Konstruktor angegeben ist:

System.Web.HttpContext.Current.Session

mit der üblichen Einschränkung, dass dies möglicherweise die Testbarkeit Ihres Controllers verringert.

Mike Chamberlain
quelle
3
Der Typ für jede dieser beiden Sitzungseigenschaften ist unterschiedlich. Dies kann von Bedeutung sein, wenn Sie einen Verweis auf den Sitzungsstatus selbst beibehalten möchten.
BrianCooksey
@BrianCooksey was ist anders?
MichaelMao
1
Controller.Session ist vom Typ System.Web.HttpSessionStateBase (siehe msdn.microsoft.com/en-us/library/… ), aber System.Web.HttpContext.Current.Session ist vom Typ System.Web.SessionState.HttpSessionState (siehe msdn .microsoft.com / en-us / library /… )
BrianCooksey
10

Die Sitzung wird später im Lebenszyklus injiziert. Warum brauchen Sie die Sitzung überhaupt im Konstruktor? Wenn Sie es für TDD benötigen, sollten Sie die Sitzung in ein verspottbares Objekt einschließen.

Andrei Rînea
quelle
1
Um Andrei Rinea hinzuzufügen, ist dies ein spezifisches Beispiel für die von ihm erwähnte Technik: iridescence.no/post/…
murki
4
Ich möchte während meiner Konstruktoren auf die Sitzung zugreifen, damit ich auf zuvor gespeicherte Sitzungsinformationen zugreifen kann. Ja, ich könnte die OnActionExecuting-Methode überschreiben, aber dies ist sicherlich keine elegante Lösung.
Chris Arnold
8

Sie können die Initialisierungsmethode überschreiben, um Ihre Sitzung festzulegen.

protected override void Initialize(RequestContext requestContext)
Funlover
quelle
2

Wenn Sie einen IoC-Container verwenden, versuchen Sie, HttpSessionStateBaseanstelle des SessionObjekts Folgendes zu injizieren und zu verwenden :

private static Container defaultContainer()
{
    return new Container(ioc =>
    {
        // session manager setup
        ioc.For<HttpSessionStateBase>()
           .Use(ctx => new HttpSessionStateWrapper(HttpContext.Current.Session)); 
    });
}
VahidN
quelle
2

Diese Antwort könnte für manche Menschen nützlich sein

Wenn wir die Initialize-Methode überschreiben, müssen wir die Basisklasse mit dem Anforderungskontext initialisieren: base.Initialize (requestContext);

protected override void Initialize(RequestContext requestContext)
        {
            base.Initialize(requestContext);
           

        }
Prashanth vunnam gcs
quelle
Nützlich. Beachten Sie, dass die Methodensignatur protected override void Initialize(System.Web.Routing.RequestContext requestContext).
Martin_W