Sesión nula en ASP.Net MVC Controller Constructors


88

¿Por qué Session es nula en los constructores de Controllers? Se puede acceder desde los métodos de acción. Presumiblemente, debido a que el marco de enrutamiento MVC es responsable de la actualización de un controlador, simplemente no ha (re) instanciado la sesión en ese momento.

¿Alguien sabe si esto es por diseño y, de ser así, por qué?

[Me las arreglé para eludir el problema utilizando un patrón de carga diferida].

Respuestas:


79

Andrei tiene razón: es nulo porque cuando se ejecuta bajo el marco ASP.NET MVC, HttpContext (y por lo tanto HttpContext.Session) no se establece cuando la clase de controlador se construye como cabría esperar, pero se establece ("inyecta") más tarde por la clase ControllerBuilder. Si desea una mejor comprensión del ciclo de vida, puede desplegar el marco ASP.NET MVC (la fuente está disponible) o consultar: esta página

Si necesita acceder a la sesión, una forma sería anular el método "OnActionExecuting" y acceder allí, ya que estará disponible en ese momento.

Sin embargo, como sugiere Andrei, si su código depende de la sesión, entonces podría ser potencialmente difícil escribir pruebas unitarias, por lo que tal vez podría considerar envolver la sesión en una clase auxiliar que luego se puede cambiar por una diferente, no versión web cuando se ejecuta bajo pruebas unitarias, por lo tanto, desacopla su controlador de la web.


3
No estoy seguro de que esta sea una declaración adecuada sobre HttpContext. En realidad, se construyó justo al comienzo de todo el flujo. Puede leer un poco sobre el flujo detallado aquí beletsky.net/2011/06/inside-aspnet-mvc-route-to-mvchanlder.html o puede usar reflector y encontrarse cuando se ha creado una instancia de httpContext, es alrededor de la línea 1556 en httpruntime .cs.
Alexey Shcherbak

@AlexeyShcherbak Puede que ya esté construido: OP se trata de si se ha configurado en la propiedad Session del controlador MVC. es decir, sesión pública HttpSessionStateBase {get; } en System.Web.Mvc.Controller Estas son cosas diferentes.
MemeDeveloper

61

Además de las otras respuestas aquí, aunque Controller.Sessionno se completa en el constructor, aún puede acceder a la sesión a través de:

System.Web.HttpContext.Current.Session

con la salvedad estándar de que esto reduce potencialmente la capacidad de prueba de su controlador.


3
El tipo de cada una de estas dos propiedades de sesión es diferente, lo que puede ser importante si tiene la intención de mantener una referencia al estado de la sesión en sí.
BrianCooksey

@BrianCooksey ¿qué es diferente?
MichaelMao

1
Controller.Session es de tipo System.Web.HttpSessionStateBase (consulte msdn.microsoft.com/en-us/library/… ) pero System.Web.HttpContext.Current.Session es de tipo System.Web.SessionState.HttpSessionState (consulte msdn .microsoft.com / en-us / library /… )
BrianCooksey

Respuesta anterior, pero quería decir que System.Web.HttpContext.Current.Sessiontambién está nullen el instanciador MVC VS2019.
jp2code

11

La sesión se inyecta más adelante en el ciclo de vida. ¿Por qué necesitas la sesión en el constructor de todos modos? Si lo necesita para TDD, debe envolver la sesión en un objeto simulado.


1
Para agregar a Andrei Rinea, este es un ejemplo específico de la técnica mencionada por él: iridescence.no/post/…
murki

4
Quiero acceder a la sesión durante mis constructores para poder tener acceso a la información de la sesión almacenada previamente. Sí, podría anular el método OnActionExecuting, pero esta ciertamente no es una solución elegante.
Chris Arnold

8

Puede anular el método Initialize para configurar su sesión.

protected override void Initialize(RequestContext requestContext)

2

Si está utilizando un contenedor de IoC, intente inyectar y usar el en HttpSessionStateBaselugar del Sessionobjeto:

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

2

Esta respuesta puede ser útil para algunas personas.

Si anulamos el método Initialize, entonces tenemos que inicializar la clase base con el contexto de la solicitud: base.Initialize (requestContext);

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

        }

Útil. Tenga en cuenta que el método signature protected override void Initialize(System.Web.Routing.RequestContext requestContext).
Martin_W
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.