【问题标题】:Session null in ASP.Net MVC Controller ConstructorsASP.Net MVC 控制器构造函数中的会话 null
【发布时间】:2009-05-20 18:34:08
【问题描述】:

为什么Controllers的构造函数中Session为null?可以从 Action 方法访问它。据推测,因为 MVC 路由框架负责更新控制器,所以它当时还没有(重新)实例化 Session。

有谁知道这是否是设计使然,如果是,为什么?

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

【问题讨论】:

    标签: asp.net-mvc session


    【解决方案1】:

    Andrei 是对的 - 它为 null,因为在 ASP.NET MVC 框架下运行时,在构造控制器类时未设置 HttpContext(以及因此 HttpContext.Session),但它设置了(“注入") 稍后由 ControllerBuilder 类调用。如果你想更好地理解生命周期可以拉下 ASP.NET MVC 框架(有源码),或者参考:this page

    如果您需要访问 Session,那么一种方法是覆盖“OnActionExecuting”方法并在那里访问它,因为届时它将可用。

    但是,正如 Andrei 所建议的,如果您的代码依赖于 Session,那么编写单元测试可能会很困难,因此也许您可以考虑将 Session 包装在一个帮助类中,然后可以将其换成不同的,在单元测试下运行时的非网络版本,因此将您的控制器与网络解耦。

    【讨论】:

    • 我不确定这是关于 HttpContext 的正确说法。它实际上是在整个流程开始时构建的。您可以在beletsky.net/2011/06/inside-aspnet-mvc-route-to-mvchanlder.html 阅读有关详细流程的一些信息,或者您可以使用反射器并在 httpContext 被实例化时找到自己 - 它在 httpruntime.cs 中的第 1556 行附近。
    • @AlexeyShcherbak 它可能已经构建了 - OP 是关于它是否已在 MVC 控制器的 Session 属性上设置。即公共 HttpSessionStateBase 会话 { get; } on System.Web.Mvc.Controller 这些是不同的东西。
    【解决方案2】:

    除了这里的其他答案,虽然Controller.Session没有填充到构造函数中,你仍然可以通过以下方式访问会话:

    System.Web.HttpContext.Current.Session

    标准警告是,这可能会降低控制器的可测试性。

    【讨论】:

    • 这两个会话属性的类型不同,如果您打算保留对会话状态本身的引用,这可能很重要。
    • @BrianCooksey 有什么不同?
    • Controller.Session 是 System.Web.HttpSessionStateBase 类型(参见 msdn.microsoft.com/en-us/library/…),但 System.Web.HttpContext.Current.Session 是 System.Web.SessionState.HttpSessionState 类型(参见 msdn.microsoft.com/en-us/library/… )
    • 旧答案,但想说System.Web.HttpContext.Current.Session在VS2019 MVC实例中也是null
    • 您可以通过使用 HttpSessionStateWrapper 构造函数包装 HttpSessionState 从 HttpSessionState 中获取 HttpSessionStateBase。
    【解决方案3】:

    Session 在生命周期的后期注入。为什么你仍然需要构造函数中的会话?如果 TDD 需要它,则应将会话包装到可模拟对象中。

    【讨论】:

    • 补充一下 Andrei Rinea,这是他提到的技术的一个具体例子:iridescence.no/post/…
    • 我想在构造函数期间访问会话,以便可以访问以前存储的会话信息。是的,我可以重写 OnActionExecuting 方法,但这肯定不是一个优雅的解决方案。
    【解决方案4】:

    您可以覆盖 Initialize 方法来设置您的会话。

    protected override void Initialize(RequestContext requestContext)
    

    【讨论】:

      【解决方案5】:

      如果您使用的是 IoC 容器,请尝试注入并使用 HttpSessionStateBase 而不是 Session 对象:

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

      【讨论】:

        【解决方案6】:

        这个答案可能对某些人有用

        如果我们重写 Initialize 方法,那么我们必须使用请求上下文初始化基类:base.Initialize(requestContext);

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

        【讨论】:

        • 有用。注意方法签名protected override void Initialize(System.Web.Routing.RequestContext requestContext).
        猜你喜欢
        • 1970-01-01
        • 2011-05-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-29
        • 1970-01-01
        • 2019-12-03
        相关资源
        最近更新 更多