0

I have a 3 page form and I'm trying to store the data of each page in a session object, but I can't figure out what's missing from my implementation

If I put a break point on NewUser newUser = GetNewUser(); the data for the object is always null on each page of the form.

For creating the session object, I'm using a helper to create a complex type.

Controller's Actions

private NewUser GetNewUser()
{
    if (HttpContext.Session.GetObjectFromJson<NewUser>("newUser") == null)
    {
        var obj = new NewUser();
        HttpContext.Session.SetObjectAsJson("newUser", obj);
    }
    return (NewUser)HttpContext.Session.GetObjectFromJson<NewUser>("newUser");
}


[HttpGet("BasicDetails")]
[HttpPost("BasicDetails")]
public IActionResult BasicDetails(BasicDetails basicDetailsModel, string prevBtn, string nextBtn)
{
    if (nextBtn != null)
    {
        if (ModelState.IsValid)
        {
            NewUser newUser = GetNewUser();
            newUser.FirstName = basicDetailsModel.FirstName;
            newUser.LastName = basicDetailsModel.LastName;
            newUser.Email = basicDetailsModel.Email;
            newUser.Password = basicDetailsModel.Password;
            newUser.Phone = basicDetailsModel.Phone;
            newUser.Country = basicDetailsModel.Country;
            newUser.City = basicDetailsModel.City;
            newUser.RecieveCommunication = basicDetailsModel.RecieveCommunication;
            return View("Views/CreateAccount/FerretDetails.cshtml");
        }
    }
    return View("Views/CreateAccount/BasicDetails.cshtml");
}

[HttpGet("FerretDetails")]
[HttpPost("FerretDetails")]
public IActionResult FerretDetails(FerretDetails ferretDetailsModel, string prevBtn, string nextBtn)
{
    NewUser newUser = GetNewUser();
    if (prevBtn != null)
    {
        BasicDetails basicDetails = new BasicDetails();
        basicDetails.FirstName = newUser.FirstName;
        basicDetails.LastName = newUser.LastName;
        basicDetails.Email = newUser.Email;
        basicDetails.Password = newUser.Password;
        basicDetails.Phone = newUser.Phone;
        basicDetails.Country = newUser.Country;
        basicDetails.City = newUser.City;
        basicDetails.RecieveCommunication = newUser.RecieveCommunication;
        return View("Views/CreateAccount/BasicDetails.cshtml", basicDetails);
    }

    if (nextBtn != null)
    {
        if (ModelState.IsValid)
        {
            newUser.FerretModel = ferretDetailsModel.FerretModel;
            newUser.FerretSerialNumber = ferretDetailsModel.FerretSerialNumber;
            newUser.PurchasedDate = ferretDetailsModel.PurchasedDate;
            newUser.PurchasedFrom = ferretDetailsModel.PurchasedFrom;
            return View("Views/CreateAccount/AccountType.cshtml");
        }
    }
    return View();
}

[HttpPost("/AccountType")]
public IActionResult AccountType(AccountType accountTypeModel, string prevBtn, int accountTypeCheck, string createBtn)
{
    NewUser newUser = GetNewUser();
    if (prevBtn != null)
    {
        FerretDetails ferretDetails = new FerretDetails();
        ferretDetails.FerretModel = newUser.FerretModel;
        ferretDetails.FerretSerialNumber = newUser.FerretSerialNumber;
        ferretDetails.PurchasedDate = newUser.PurchasedDate;
        ferretDetails.PurchasedFrom = newUser.PurchasedFrom;
        return View("Views/CreateAccount/FerretDetails.cshtml", ferretDetails);
    }
    if (createBtn != null)
    {
        if (ModelState.IsValid)
        {

        }
    }
    return View();
}

Helper class

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 value = session.GetString(key);

        return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
    }
}
Peter Csala
  • 17,736
  • 16
  • 35
  • 75
Ryn901
  • 173
  • 2
  • 12

1 Answers1

0

If I put a break point on NewUser newUser = GetNewUser(); the data for the object is always null on each page of the form.

According to your code, I have created a sample, it seems that the GetNewUser() method will always return a new user, it will not be null.

Since you are putting the break point on NewUser newUser = GetNewUser();, perhaps this statement is not executed, so when you check the value it will show null, like this:

enter image description here

After executed the statement (try to press "F10" or "F11" Key), then, you will get the value:

enter image description here

Besides, about the session value lost issue, you could check the following tips:

  1. Refer the Session and state management in ASP.NET Core to configure session state (the order of middleware is important):

    Add a call to AddSession in ConfigureServices.
    Add a call to UseSession in Configure.

  2. Check the browser setting, make sure it Enable the session and cookie.

  3. Check the session Configuration, make sure it's not expired.

  4. If you are using asp.net core 2.1 or 2.2 version, in the ConfigureServices method of the Startup class, try to set options.CheckConsentNeeded = context => false;

     services.Configure<CookiePolicyOptions>(options =>
     {
       // This lambda determines whether user consent for non-essential cookies is needed for a given request.
       options.CheckConsentNeeded = context => false;
       options.MinimumSameSitePolicy = SameSiteMode.None;
     });
    

    Reference: Session variable value is getting null in ASP.NET Core

Edit:

Test steps:

  1. Create a new asp.net core MVC application,

  2. Add session in the Startup.cs class:

     public void ConfigureServices(IServiceCollection services)
     { 
         services.AddSession(options =>
         {
             options.IdleTimeout = TimeSpan.FromMinutes(10);
             options.Cookie.HttpOnly = true;
             options.Cookie.IsEssential = true;
         });
         services.AddControllersWithViews();
         services.AddRazorPages();
     }
    
     // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
     public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
     {
         ...
    
         app.UseSession();
         app.UseEndpoints(endpoints =>
         {
             endpoints.MapControllerRoute(
                 name: "default",
                 pattern: "{controller=Home}/{action=Index}/{id?}");
             endpoints.MapRazorPages();
         });
     }
    
  3. Add SessionExtensions.cs:

    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 value = session.GetString(key);
    
         return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
     }
    

    }

  4. Add a NewUser class, contains two properties: UserID and UserName.

  5. Use the following code to test the session:

     public IActionResult Index()
     {
         NewUser newUser = GetNewUser();
    
         var usename = newUser.UserName;
    
         if (HttpContext.Session.GetObjectFromJson<NewUser>("TestData") == null)
         {
             var obj = new NewUser() { UserID = 1001, UserName = "Tom" };
             HttpContext.Session.SetObjectAsJson("TestData", obj);
         }
         return View();
     }
     private NewUser GetNewUser()
     {
         if (HttpContext.Session.GetObjectFromJson<NewUser>("newUser") == null)
         {
             var obj = new NewUser() { UserID=1001, UserName="Jack" };
             HttpContext.Session.SetObjectAsJson("newUser", obj);
         }
    
    
         return (NewUser)HttpContext.Session.GetObjectFromJson<NewUser>("newUser");
     }
    
     public IActionResult Privacy()
     {
         NewUser newUser = GetNewUser();
         var usename = newUser.UserName;
    
         if (HttpContext.Session.GetObjectFromJson<NewUser>("TestData") != null)
         {
             var name = HttpContext.Session.GetObjectFromJson<NewUser>("TestData").UserName;
         }
         return View();
     }
    

Then, check the debug screenshot(we could get the value from the session):

enter image description here

Zhi Lv
  • 18,845
  • 1
  • 19
  • 30
  • Sorry, I should have been more clear. Yes the object itself is not null, but I meant it doesn't store the values from the previous page. I had already added both services.AddSession(options => { options.IdleTimeout = TimeSpan.FromSeconds(120); options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; }); and app.UseSession(); – Ryn901 Oct 07 '20 at 23:07
  • Whether the browser disable the Session/cookie or not? On my side, if browser disable the session and cookie, the session will be null in the application. – Zhi Lv Oct 08 '20 at 15:24
  • Chrome is set to enable all cookies, but session object still doesn't have data from previous page in the form – Ryn901 Oct 11 '20 at 05:09
  • I also checked it using a .net core 3.1 application, the session works well. I suggest you could try to create a new sample and refer the [Session state](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/app-state?view=aspnetcore-3.1#session-state) document, then try to use a different browser to check whether it works well or not. – Zhi Lv Oct 12 '20 at 07:31
  • I've read that document a few times now. I haven't tried it using just strings instead of complex objects though and sol I will try that. Did it work for you when using the helper class above? – Ryn901 Oct 12 '20 at 19:57
  • Yes, they all work well in my .net core 3.1 web application. – Zhi Lv Oct 13 '20 at 07:13
  • Thanks for testing but it's still not working for me. My startup class is exactly like the docs say to do it, the correct services and the correct order, but NewUser newUser = GetNewUser(); is always has null items at each subsequent action – Ryn901 Oct 15 '20 at 07:19
  • would you be able to share the action methods and helper you set up in your test app? – Ryn901 Oct 15 '20 at 07:52
  • @Ryn901 Please check my Edit in the reply. – Zhi Lv Oct 15 '20 at 08:48
  • If I create a new project and create a basic setup like the above, it works, but still not in the code of my actual project. On the first step a new object is created using HttpContext.Session.Set("User", obj); in the next step, a new object is not create and the exisiting object is returned. So far so good. The returned object has no values though and so user.FirstName = basicDetailsModel.FirstName; etc is not saving the new values. I can iterate over as they are being set and I can see the data being assigned, but it's not being stored – Ryn901 Oct 19 '20 at 01:47