Search code examples
asp.net-coresessionhttpcontext

How can I access session data in Asp.net MVC Core 7?


I'm in the process of migrating a huge project from .net4.8 to .net7.

The solution is basically a tiny web core project called Investo, but it references a huge project called General. 99% of the logic is in General.

in General I have loads of calls to a function called GetUserID, this function (in asp.net 4.8) returns a parameter stored in the HttpContext.Current.Session. works great for 10 years.

But now when I call it from .net7, which removed the HttpContext.Current, I can't figure out how to access the state in arbitrary code.

I tried storing it in a global shared variable, but it seems to randomly get disposed or other random errors.

Here is the relevant part of my program.cs

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpContextAccessor();
builder.Services.AddSession();
builder.Services.AddControllersWithViews();
builder.Services.AddSingleton<WebData>();
builder.Services.AddScoped<WebData>();
var app = builder.Build();

app.UseStaticFiles();
app.UseRouting();
app.UseSession();

Core.Options.PersonID = () =>
{
    var ses = WebData.CurSession();
    if (ses == null) return null;
    var sessionData = ses.GetString("WebSession");
    if (sessionData == null) return null;
    var ws = JsonConvert.DeserializeObject<WebSession>(sessionData);
    return ws.PersonID;
};

app.MapGet("/Global/InvokeFunction", (string Name, string JsonInput, HttpContext httpContext) =>
{
    //return WebFunctions.InvokeFunction(Name, JsonInput);
    //var a = new WebData();
    WebData.WebContext = httpContext;
    //if(WebData.WebContext ==null)   WebData.WebContext = httpContext;
    var uid = Core.Functions.GetUserID();
    var ret = Web.WebFunctions.InvokeFunction(Name, JsonInput);
    var json = Utils.Extensions.ToSafeJson(ret);
    return Results.Content(json, "application/json");
});

app.Run();

Here is WebData:

public class WebData
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public WebData(IHttpContextAccessor httpContextAccessor) {
        _httpContextAccessor = httpContextAccessor; // never fires
    }
     
    static public HttpContext WebContext { get; set; }
    static public ISession? CurSession() {
        var cx = WebContext;
        if (cx == null) return null; //OK. maybe background threads etc.
        try {
            var ses = cx.Session; //this often fails with "object reference not set to instance of an object". even if its a try-catch. 
            return ses;
        }
        catch (Exception ex) {
            if (!ex.Message.StartsWith("IFeat")) {
                var b = 1;//happens often can figure out rhyme or reason why and when it happens. sometimes works sometimes not
            }
            var a = ex;
        }
        return null;
    }
}

The first 3 lines (regarding IHttpContextAccessor) I added since I read that it somehow is supposed to help, though in fact it never fires.

Please advise how I can access current session information down the pipeline of MapGet> InvokeFunction> my whole code base.

If necessary, I'd be glad to provide any additional information.

Thanks in advance!

Update 1

Removing AddSingleton and AddScoped seem to have no effect. To the contrary, I think I now have more errors.


Solution

  • My solution for this was

    1. Changed the helper Web Data to a Static class & methods so the WebData looks:
    public static class WebData
    {
        private static IHttpContextAccessor _httpContextAccessor;
        public static void Init(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }
        public static HttpContext? WebContext()
        {
            if (_httpContextAccessor != null)
                return _httpContextAccessor.HttpContext;
            return null;
        }
        public static ISession? CurSession()
        {
            //var cx = _httpContextAccessor.HttpContext;
            var cx = WebContext();
            if (cx == null) return null;
            try
            {
                var ses = cx.Session;
                return ses;
            }
            catch (Exception ex)
            {
                //if (!ex.Message.StartsWith("IFeat"))
                //{
                //    var b = 1;
                //}
                //var a = ex;
            }
            return null;
        }
    }
    
    1. Added WebData.Init(builder.Services.BuildServiceProvider().GetRequiredService<IHttpContextAccessor>()); to Program.cs.