9

In earlier version of Asp.Net session can be accessed in any page like a static variable using

System.Web.HttpContext.Current.Session["key"]

In Asp.Net Core, How to access session in different class called via controller, without passing the session property as an additional parameter in the constructor of all classes

RonC
  • 31,330
  • 19
  • 94
  • 139
Navaneeth
  • 447
  • 3
  • 8
  • 16
  • 2
    How about reading the docs? It's very well described at this stage of ASP.NET Core: https://docs.asp.net/en/latest/fundamentals/app-state.html#installing-and-configuring-session – Tseng Jun 13 '16 at 09:16
  • in all the samples i saw in that site, i can see only "HttpContext objContext" object passed as a parameter to the method / delegate, and session is accessed as objContext.Session. I thought like someway will be available like earlier Asp.Net , something like HttpContext.Current.Session , so that passing an extra parameter can be avoided – Navaneeth Jun 13 '16 at 09:35
  • 2
    Inside a controller you have access to HttpContext (if controller derives from `Controller` base class) otherwise you have to inject `IHttpContextAccessor` – Tseng Jun 13 '16 at 10:09

3 Answers3

23

Revised approach 1/17/17 to fix bug

First, I'll assume that you have your ASP.NET Core application configured to use session state. If not see @slfan's answer How to access the Session in ASP.NET Core via static variable?

How to access session in different class called via controller, without passing the session property as an additional parameter in the constructor of all classes

Asp.Net Core is designed around dependency injection and in general the designers didn't provide much static access to context information. More specifically there is no equivalent to System.Web.HttpContext.Current.

In Controllers you can get access to Session vars via this.HttpContext.Session but you specifically asked how to get access to the session from methods called by the controller without passing the session property as a parameter.

So, to do this we need to setup our own static class to provide access to session and we need some code to initialize that class at startup. Since it's likely that a person may want static access to the whole HttpContext object and not just the Session I took that approach.

So first we need the static class:

using Microsoft.AspNetCore.Http; 
using System;
using System.Threading;

namespace App.Web {

    public static class AppHttpContext {
        static IServiceProvider services = null;

        /// <summary>
        /// Provides static access to the framework's services provider
        /// </summary>
        public static IServiceProvider Services {
            get { return services; }
            set {
                if(services != null) {
                    throw new Exception("Can't set once a value has already been set.");
                }
                services = value;
            }
        }

        /// <summary>
        /// Provides static access to the current HttpContext
        /// </summary>
        public static HttpContext Current {
            get {
                IHttpContextAccessor httpContextAccessor = services.GetService(typeof(IHttpContextAccessor)) as IHttpContextAccessor;
                return httpContextAccessor?.HttpContext;
            }
        } 

    }
}

Next we need to add a service to the DI container that can provide access to the current HttpContext. This service ships with the Core MVC framework but is not installed by default. So we need to "install" it with a single line of code. This line goes in the ConfigureServices method of the Startup.cs file and can be located anywhere in that method:

//Add service for accessing current HttpContext
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();    

Next we need to setup our static class so that it has access to the DI container to obtain the service we just installed. The code below goes in the Configure method of the Startup.cs file. This line can be be located anywhere in that method:

AppHttpContext.Services = app.ApplicationServices; 

Now any method called by the Controller, even via the async await pattern, can access the current HttpContext via AppHttpContext.Current

So, if we use the Session extension methods in the Microsoft.AspNetCore.Http namespace, we can save an int called "Count" to session could be done like this:

AppHttpContext.Current.Session.SetInt32("Count", count);

And retrieving an int called "Count" from session could be done like this:

int count count = AppHttpContext.Current.Session.GetInt32("Count");

Enjoy.

RonC
  • 31,330
  • 19
  • 94
  • 139
  • 1
    @ Ron C Great answer. A notice to others, replace `await next();` with `await next.Invoke();` in **Core 1.0** – Shittu Joseph Olugbenga Jul 26 '16 at 11:12
  • This is one of the most sensible answers I have seen regarding "global session access solution". Does this approach have some drawbacks when compared to dependency injection approach? I'v been trying to figure out how I should implement access to "app-specific configuration variables" (read: "env variables", user/thread/httpContext-specific) and most examples are using depency injection approach. I'm bit hesitant on having the need to add httpContext as param for every constructor when accessing form controllers, as it's possible that some methods may end up being static. – Janne Jul 18 '22 at 11:33
4

In Startup.ConfigureServices you have to add the service

services.AddSession();

and in the method Configure you have to use it (important: call before app.UseMvc())

app.UseSession();

Now you can use it in your controllers (if derived from Controller). You can store

var data = new byte[] { 1, 2, 3, 4 };
HttpContext.Session.Set("key", data); // store byte array

byte[] readData;
HttpContext.Session.TryGetValue("key", out readData); // read from session

When you import the namespace Microsoft.AspNetCore.Http then you can use SetString and SetInt32 as well.

using Microsoft.AspNetCore.Http;

HttpContext.Session.SetString("test", "data as string"); // store string
HttpContext.Session.SetInt32("number", 4711); // store int

int ? number = HttpContext.Session.GetInt32("number");

Outside the controller you do not have access to the HttpContext, but you can inject an IHttpContextAccessor instance like described in this answer

slfan
  • 8,950
  • 115
  • 65
  • 78
  • What should I do if I don't know the size that data byte[] should be? – user8128167 Jun 11 '19 at 20:39
  • @user8128167 what do you mean with you don't know the size of the byte array? In .NET the size of a data array is always known. Or did I misunderstand your question? – slfan Jun 12 '19 at 09:28
  • I mean if I'm going to call "HttpContext.Session.TryGetValue("key", out data);" then shouldn't I know the size in bytes that data is going to need to be to get the value out of session based on "key"? – user8128167 Jun 12 '19 at 13:39
  • @user8128167 No, as 'data' is an out parameter, the byte array will be allocated. It would be rather stupid if you had to know the size of the stored data beforehand. You normally read the Session date in a different controller/action. – slfan Jun 12 '19 at 18:23
  • Good point, I totally missed that "out" keyword so thanks. Perhaps your answer would be more clear if you put var data = new byte[] {}; instead of "var data = new byte[] { 1, 2, 3, 4 };"? – user8128167 Jun 12 '19 at 18:57
3

If you want to store and retrieve a complex object from Session, you could instead use these extensions:

public static class SessionExtensions
{
    public static void SetObjectAsJson(this ISession session, string key, object value)
    {
        session.SetString(key, JsonConvert.SerializeObject(value));
    }

    public static T GetObjectFromJson<T>(this ISession session, string key)
    {
        var data = session.GetString(key);  
        if (data == null)  
        {  
            return default(T);  
        }  
        return JsonConvert.DeserializeObject<T>(data);
    }
}

Then you would call them like this:

User user = new User();  
user.Name = "Jignesh Trivedi";  
user.Percentage = 75.45;             

HttpContext.Session.SetComplexData("UserData", user); 

Or,

ViewBag.data = HttpContext.Session.GetComplexData<User>("UserData");  

For details, please see https://www.c-sharpcorner.com/article/session-state-in-asp-net-core/

user8128167
  • 6,929
  • 6
  • 66
  • 79