2009-05-20 38 views
80

Dlaczego w konstruktorach kontrolerów jest pusta sesja? Dostęp do niego można uzyskać za pomocą metod działania. Można przypuszczać, że ponieważ struktura routingu MVC jest odpowiedzialna za stworzenie nowego kontrolera, to po prostu nie zreorganizowała sesji w tym momencie.Sesja zerowa w konstruktorze kontrolerów ASP.Net MVC

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

[I udało się obejść ten problem za pomocą Lazy Loading Wzorzec.]

Odpowiedz

68

Andrei ma rację - jest pusty, ponieważ podczas działania w środowisku ASP.NET MVC, HttpContext (a zatem HttpContext.Session) nie jest ustawiany, gdy klasa kontrolera jest kontruktowana zgodnie z oczekiwaniami, ale jest ustawiona (" wstrzykiwany ") później przez klasę ControllerBuilder. Jeśli chcesz lepiej poznać cykl życia, możesz albo usunąć platformę ASP.NET MVC (źródło jest dostępne), albo: this page

Jeśli potrzebujesz dostępu do sesji, jednym ze sposobów byłoby pominięcie metodę "OnActionExecuting" i uzyskaj do niej dostęp, ponieważ będzie ona dostępna do tego czasu.

Jednak, jak sugeruje Andrei, jeśli twój kod jest zależny od sesji, może to być trudne do napisania testów jednostkowych, więc może powinieneś rozważyć zawinięcie sesji w klasie pomocnika, która może zostać zamieniona na inną, niesieciową wersję, gdy uruchamiana jest w ramach testów jednostkowych, w związku z czym odłącza kontroler od sieci.

+1

Nie jestem pewien, czy jest to prawidłowe oświadczenie o HttpContext. Faktycznie skonstruowano na początku całego przepływu. Możesz przeczytać trochę o szczegółowym przepływie tutaj http://www.beletsky.net/2011/06/inside-aspnet-mvc-route-to-mvchanlder.html lub możesz użyć reflektora i znaleźć się, gdy zostanie utworzone instancja httpContext - jego linia około 1556 w httpruntime.cs. –

+0

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

10

sesja jest wstrzykiwany później w cyklu życia. Dlaczego mimo wszystko potrzebujesz sesji w konstruktorze? Jeśli potrzebujesz go do TDD, powinieneś owinąć sesję w obiekt, który można zabezpieczyć.

+1

dodać do Andrei Rinea, jest to konkretny przykład techniki wspomnianym przez niego : http://iridescence.no/post/Using-Unit-Tests-to-Uncover-Design-Flaws.aspx – murki

+4

Chcę uzyskać dostęp do sesji podczas moich konstruktorów, aby uzyskać dostęp do wcześniej zapisanych informacji o sesji. Tak, mogłem zastąpić metodę OnActionExecuting, ale z pewnością nie jest to eleganckie rozwiązanie. –

+0

@ChrisArnold, zobacz moją odpowiedź. –

50

Oprócz innych odpowiedzi tutaj, natomiast Controller.Session nie jest wypełniana w konstruktorze, nadal można uzyskać dostęp do sesji poprzez:

System.Web.HttpContext.Current.Session

ze standardowym zastrzeżeniem, że to potencjalnie zmniejsza testowalności Twojego sterownika.

+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

+0

@BrianCooksey co jest innego? – MichaelMao

+1

Controller.Session jest typu System.Web.HttpSessionStateBase (patrz https://msdn.microsoft.com/en-us/library/system.web.mvc.controller.session(v=vs.118).aspx), ale System.Web.HttpContext.Current.Session jest typu System.Web.SessionState.HttpSessionState (patrz https://msdn.microsoft.com/en-us/library/system.web.httpcontext.session(v=vs.110) .aspx) – BrianCooksey

6

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

protected override void Initialize(RequestContext requestContext) 
2

Jeśli używasz kontenera IoC, spróbuj wstrzykiwanie i przy użyciu HttpSessionStateBase zamiast obiektu Session:

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