92

Why is Session null in the constructors of Controllers? It can be accessed from Action methods. Presumably, because the MVC Routing framework is responsible for newing-up a Controller, it just hasn't (re-)instantiated the Session at that point.

Does anyone know if this is by design and, if so, why?

[I have managed to circumvent the problem by using a Lazy Loading Pattern.]

1
  • Yeah, this is a bit old but ... Ran into that problem. Seems to me that the HttpContext is created as part of the constructor so not available there. I removed refernce to it from the constructor and inserted same code in a Controller Get method and it worked! Commented Sep 21, 2024 at 2:42

6 Answers 6

82

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.

Sign up to request clarification or add additional context in comments.

2 Comments

I don't sure this is proper statement about HttpContext. It actually constructed right at start of entire flow. You can read a bit about detailed flow here beletsky.net/2011/06/inside-aspnet-mvc-route-to-mvchanlder.html or you can use reflector and find yourself when httpContext have been instantiated - its around line 1556 in httpruntime.cs.
@AlexeyShcherbak It may be constructed already - OP is about whether it has been set on the MVC controller's Session property. i.e. public HttpSessionStateBase Session { get; } on System.Web.Mvc.Controller These are different things.
66

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.

5 Comments

The type for each of these two session properties is different, which may matter if you intend to keep a reference to the session state itself.
@BrianCooksey what's different?
Controller.Session is of type System.Web.HttpSessionStateBase (see msdn.microsoft.com/en-us/library/…) but System.Web.HttpContext.Current.Session is of type System.Web.SessionState.HttpSessionState (see msdn.microsoft.com/en-us/library/…)
Old answer, but wanted to say that System.Web.HttpContext.Current.Session is also null in VS2019 MVC instanciator.
You can get a HttpSessionStateBase from a HttpSessionState by wrapping it using the HttpSessionStateWrapper constructor.
11

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.

2 Comments

To add to Andrei Rinea, this is a specific example of the technique mentioned by him: iridescence.no/post/…
I want to access the Session during my constructors so that I can have access to previously stored session information. Yes, I could override the OnActionExecuting method, but this certainly isn't an elegant solution.
8

You can override the Initialize method to set your session.

protected override void Initialize(RequestContext requestContext)

Comments

2

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)); 
    });
}

Comments

2

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);
           

        }

1 Comment

Useful. Note that the method signature protected override void Initialize(System.Web.Routing.RequestContext requestContext).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.