NET MVC 控制器构造函数中的 Session null

为什么在控制器的构造函数中会话为空?可以从 Action 方法访问它。可以推测,由于 MVC 路由框架负责更新 Controller,所以在那个时候它还没有(重新)实例化 Session。

有人知道这是不是故意的,如果是,为什么?

[我已经设法通过使用懒惰加载模式来规避这个问题。]

66596 次浏览

The Session is injected later in the life-cycle. Why do you need the session in the constructor anyway? If you need it for TDD you should wrap the session into a mockable object.

Andrei is right - it is null because when running under the ASP.NET MVC framework, the HttpContext (and therefore HttpContext.Session) is not set when the controller class is contructed as you might expect, but it set ("injected") later by the ControllerBuilder class. If you want a better understanding of the lifecycle you can either pull down the ASP.NET MVC framework (the source is available), or refer to: this page

If you need to access the Session then one way would be to override the "OnActionExecuting" method and access it there, as it will be available by that time.

However, as Andrei is suggesting, if your code is reliant on the Session then it could potentially be difficult to write unit tests, so perhaps you could consider wrapping the Session in a helper class which can then be swapped out for a different, non-web version when running under unit tests, therefore de-coupling your controller from the web.

In addition to the other answers here, while Controller.Session is not populated in the constructor, you can still access the session through:

System.Web.HttpContext.Current.Session

with the standard caveat that this potentially reduces your controller's testability.

You can override the Initialize method to set your session.

protected override void Initialize(RequestContext requestContext)

If you are using an IoC Container, try injecting and using the HttpSessionStateBase instead of the Session object:

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

This answer might be useful for some people

If we override Initialize method then we have to initialize base class with request context : base.Initialize(requestContext);

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



}