Sesja null w konstruktorach kontrolera ASP.Net MVC


88

Dlaczego sesja ma wartość null w konstruktorach kontrolerów? Można uzyskać do niego dostęp z metod akcji. Przypuszczalnie, ponieważ struktura routingu MVC jest odpowiedzialna za utworzenie nowego kontrolera, po prostu nie utworzyła (ponownie) wystąpienia sesji w tym momencie.

Czy ktoś wie, czy jest to zgodne z projektem, a jeśli tak, to dlaczego?

[Udało mi się obejść problem, używając wzorca leniwego ładowania.]

Odpowiedzi:


79

Andrei ma rację - ma wartość null, ponieważ podczas uruchamiania w ramach ASP.NET MVC HttpContext (a tym samym HttpContext.Session) nie jest ustawiana, gdy klasa kontrolera jest konstruowana zgodnie z oczekiwaniami, ale jest ustawiana („wstrzykiwana”) później przez klasę ControllerBuilder. Jeśli chcesz lepiej zrozumieć cykl życia, możesz rozwinąć strukturę ASP.NET MVC (źródło jest dostępne) lub zapoznać się z: tą stroną

Jeśli potrzebujesz dostępu do sesji, jednym ze sposobów byłoby zastąpienie metody „OnActionExecuting” i dostęp do niej, ponieważ będzie ona dostępna do tego czasu.

Jednak, jak sugeruje Andrei, jeśli twój kod jest zależny od sesji, wtedy pisanie testów jednostkowych może być trudne, więc być może warto rozważyć umieszczenie sesji w klasie pomocniczej, którą można następnie zamienić na inną, wersja internetowa podczas uruchamiania w ramach testów jednostkowych, dlatego należy odłączyć kontroler od sieci.


3
Nie jestem pewien, czy jest to właściwe stwierdzenie dotyczące HttpContext. Właściwie skonstruował się na początku całego przepływu. Możesz przeczytać trochę o szczegółowym przepływie tutaj beletsky.net/2011/06/inside-aspnet-mvc-route-to-mvchanlder.html lub możesz użyć reflektora i dowiedzieć się, kiedy utworzono wystąpienie httpContext - jest to około linii 1556 w httpruntime .cs.
Alexey Shcherbak

@AlexeyShcherbak Może być już skonstruowane - OP dotyczy tego, czy zostało ustawione we właściwości Session kontrolera MVC. tj. publiczna sesja HttpSessionStateBase {get; } on System.Web.Mvc.Controller To są różne rzeczy.
MemeDeveloper

61

Oprócz innych odpowiedzi tutaj, chociaż Controller.Sessionnie jest to wypełnione w konstruktorze, nadal możesz uzyskać dostęp do sesji poprzez:

System.Web.HttpContext.Current.Session

ze standardowym zastrzeżeniem, że potencjalnie zmniejsza to testowalność kontrolera.


3
Typ każdej z tych dwóch właściwości sesji jest inny, co może mieć znaczenie, jeśli zamierzasz zachować odniesienie do samego stanu sesji.
BrianCooksey

@BrianCooksey what's different?
MichaelMao

1
Controller.Session jest typu System.Web.HttpSessionStateBase (patrz msdn.microsoft.com/en-us/library/… ), ale System.Web.HttpContext.Current.Session jest typu System.Web.SessionState.HttpSessionState (patrz msdn .microsoft.com / en-us / library /… )
BrianCooksey

Stara odpowiedź, ale chciałem powiedzieć, że System.Web.HttpContext.Current.Sessionjest również nullw instancjatorze VS2019 MVC.
jp2code

11

Sesja jest wstrzykiwana później w cyklu życia. Dlaczego i tak potrzebujesz sesji w konstruktorze? Jeśli potrzebujesz go do TDD, powinieneś zawinąć sesję w obiekt, który można wyrejestrować.


1
Aby dodać Andreiowi Rinei, oto konkretny przykład wspomnianej przez niego techniki: iridescence.no/post/…
murki

4
Chcę uzyskać dostęp do sesji podczas moich konstruktorów, aby mieć dostęp do wcześniej zapisanych informacji o sesji. Tak, mógłbym zastąpić metodę OnActionExecuting, ale z pewnością nie jest to eleganckie rozwiązanie.
Chris Arnold

8

Możesz zastąpić metodę Initialize, aby ustawić sesję.

protected override void Initialize(RequestContext requestContext)

2

Jeśli używasz kontenera IoC, spróbuj wstrzyknąć i użyć HttpSessionStateBasezamiast Sessionobiektu:

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

2

Ta odpowiedź może być przydatna dla niektórych osób

Jeśli nadpisujemy metodę Initialize, musimy zainicjować klasę bazową z kontekstem żądania: base.Initialize (requestContext);

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

        }

Przydatny. Zwróć uwagę, że podpis metody protected override void Initialize(System.Web.Routing.RequestContext requestContext).
Martin_W
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.