Sessione null nei costruttori di controller ASP.Net MVC


88

Perché la sessione è nulla nei costruttori dei controller? È possibile accedervi dai metodi di azione. Presumibilmente, poiché il framework MVC Routing è responsabile dell'aggiornamento di un controller, a quel punto non ha (ri) istanziato la sessione.

Qualcuno sa se questo è di progettazione e, in tal caso, perché?

[Sono riuscito a aggirare il problema utilizzando un modello di caricamento lento.]

Risposte:


79

Andrei ha ragione: è nullo perché durante l'esecuzione nel framework ASP.NET MVC, HttpContext (e quindi HttpContext.Session) non è impostato quando la classe controller è costruita come ci si potrebbe aspettare, ma viene impostata ("iniettata") in seguito dalla classe ControllerBuilder. Se desideri una migliore comprensione del ciclo di vita, puoi eseguire il pull down del framework ASP.NET MVC (la fonte è disponibile) o fare riferimento a: questa pagina

Se è necessario accedere alla sessione, un modo sarebbe sovrascrivere il metodo "OnActionExecuting" e accedervi da lì, poiché sarà disponibile da quel momento.

Tuttavia, come suggerisce Andrei, se il tuo codice fa affidamento sulla sessione, potrebbe essere potenzialmente difficile scrivere test unitari, quindi forse potresti considerare di racchiudere la sessione in una classe helper che può quindi essere sostituita con una diversa, non versione web durante l'esecuzione in unit test, quindi scollega il tuo controller dal web.


3
Non sono sicuro che questa sia un'affermazione corretta su HttpContext. In realtà è stato costruito proprio all'inizio dell'intero flusso. Puoi leggere un po 'sul flusso dettagliato qui beletsky.net/2011/06/inside-aspnet-mvc-route-to-mvchanlder.html oppure puoi usare reflector e ritrovarti quando httpContext è stato istanziato - è intorno alla riga 1556 in excludedpruntime .cs.
Alexey Shcherbak

@AlexeyShcherbak Potrebbe essere già costruito - OP riguarda se è stato impostato sulla proprietà Session del controller MVC. cioè pubblico HttpSessionStateBase Session {get; } su System.Web.Mvc.Controller Queste sono cose diverse.
MemeDeveloper

61

Oltre alle altre risposte qui, sebbene Controller.Sessionnon sia popolato nel costruttore, è comunque possibile accedere alla sessione tramite:

System.Web.HttpContext.Current.Session

con l'avvertenza standard che questo riduce potenzialmente la testabilità del controller.


3
Il tipo di ciascuna di queste due proprietà di sessione è diverso, il che può essere importante se si intende mantenere un riferimento allo stato della sessione stesso.
BrianCooksey

@BrianCooksey cosa c'è di diverso?
MichaelMao

1
Controller.Session è di tipo System.Web.HttpSessionStateBase (vedere msdn.microsoft.com/en-us/library/… ) ma System.Web.HttpContext.Current.Session è di tipo System.Web.SessionState.HttpSessionState (vedere msdn .microsoft.com / en-us / library /… )
BrianCooksey

Vecchia risposta, ma volevo dire che System.Web.HttpContext.Current.Sessionè anche nullnell'istituto MVC VS2019.
jp2code

11

La sessione viene iniettata più tardi nel ciclo di vita. Perché hai comunque bisogno della sessione nel costruttore? Se ne hai bisogno per TDD dovresti racchiudere la sessione in un oggetto mockable.


1
Per aggiungere ad Andrei Rinea, questo è un esempio specifico della tecnica da lui menzionata: iridescence.no/post/…
murki

4
Voglio accedere alla sessione durante i miei costruttori in modo da poter avere accesso alle informazioni sulla sessione memorizzate in precedenza. Sì, potrei sovrascrivere il metodo OnActionExecuting, ma questa non è certamente una soluzione elegante.
Chris Arnold,

8

È possibile ignorare il metodo Initialize per impostare la sessione.

protected override void Initialize(RequestContext requestContext)

2

Se stai utilizzando un contenitore IoC, prova a iniettare e utilizzare HttpSessionStateBaseinvece Sessiondell'oggetto:

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

2

Questa risposta potrebbe essere utile per alcune persone

Se sovrascriviamo il metodo Initialize, dobbiamo inizializzare la classe base con il contesto della richiesta: base.Initialize (requestContext);

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

        }

Utile. Nota che la firma del metodo protected override void Initialize(System.Web.Routing.RequestContext requestContext).
Martin_W
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.