Strongly typed TempData in Core

Viewed 191

With Web Forms, I could create a wrapper for a strongly typed Session:

public class MySession
{
    public static MySession Current
    {
        get
        {
            MySession session = (MySession)HttpContext.Current.Session["__MySession__"];

            if (session == null)
            {
                session = new MySession();
                HttpContext.Current.Session["__MySession__"] = session;
            }

            return session;
        }
    }

    public string TestString { get; set; }
}

I am trying to do the same thing for TempData in Core:

public class MySession
{
    public static MySession Current
    {
        get
        {
            var _sessionId = "_MyTempData_";

            var httpContext = new HttpContextAccessor().HttpContext;
            var tempDataFactory = httpContext.RequestServices.GetRequiredService<ITempDataDictionaryFactory>();
            var tempData = tempDataFactory.GetTempData(httpContext);

            var val = tempData.Peek(_sessionId) as string;

            MySession mySession;
            if (string.IsNullOrWhiteSpace(val))
            {
                mySession = new();
                tempData[_sessionId] = JsonConvert.SerializeObject(mySession);
                tempData.Save();
            }
            else
                mySession = JsonConvert.DeserializeObject<MySession>(val);

            return mySession;
        }
    }

    public string TestString { get; set; }

}

But my TestString value is alway null:

MySession.Current.TestString = "Test";
var x = MySession.Current.TestString //always null

Is it because I was able to store the actual MySession object, so it was referenced, or something?

2 Answers

Please note, in .net core it is no good practice to use HttpContext class to store data state.

There are designated classes that do the operations, cleaner and with more efficiency. In your case, in order to store session state you can use the Isession interface.

It implements the traditional Get, Set methods for string and int (int32, int16).

The link I attached should cover the use cases and give you a hint on how to use this.

What about using a non-static class and separating the data from the logic?

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Newtonsoft.Json;

namespace Test
{
    // Add to Startup.cs
    // services.AddScoped<SessionService>();

    public class SessionService
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly ITempDataDictionaryFactory _tempDataDictionaryFactory;
        private readonly string _sessionId = "_MyTempData_";
        
        public SessionService(IHttpContextAccessor httpContextAccessor, ITempDataDictionaryFactory tempDataDictionaryFactory)
        {
            _httpContextAccessor = httpContextAccessor;
            _tempDataDictionaryFactory = tempDataDictionaryFactory;
        }

        public SessionData Current
        {
            get
            {
                var httpContext = _httpContextAccessor.HttpContext;
                var tempData = _tempDataDictionaryFactory.GetTempData(httpContext);

                var val = tempData.Peek(_sessionId) as string;

                SessionData mySession;
                if (string.IsNullOrWhiteSpace(val))
                {
                    mySession = new();
                    tempData[_sessionId] = JsonConvert.SerializeObject(mySession);
                    tempData.Save();
                }
                else
                    mySession = JsonConvert.DeserializeObject<SessionData>(val);

                return mySession;
            }
            
        }
    }
}

Separate class for the data,

namespace Test
{
     public class SessionData
     {
        public string TestString { get; set; }
     }
}

Usage in a ASP.NET Core webpage:

namespace Test
{
    [Authorize]
    public class HomeController : Controller
    {
        private readonly SessionService _sessionService;
        private SessionData SessionData => _sessionService.Current;

        public HomeController(SessionService sessionService)
        {
            _sessionService = sessionService;
        }
        
        [HttpGet]
        public IActionResult Index()
        {
            var hi = SessionData.TestString;
            
            return View(hi);
        }
    }
}
    
Related