Reputation: 1
I have just started with asp.net Core 3.1 and ran into a problem with using the Session variable(s) to store user login data, basically it returns 'null' randomly when switching between pages or doing an ajax post. I have spend hours on this googling and trying everything I have seen, to no avail. I eventually created a new Razor page web app and I still get the problem with the session variables returning null. To re-produce this, click on the 'Save Changes' button, it will do the HTTP Post, and the session variable 'Index' is null.
I hope someone can help here.
<HTML>
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<script type="text/javascript">
$("body").on("click", ".Save", function (e) {
if (confirm("Do you want to Save all your changes?")) {
var bd = ["test:", "mike"];
$.ajax({
type: "POST",
url: "/Index?handler=Fred",
cache: false,
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
data: JSON.stringify(bd),
contentType: "application/json; charset=utf-8",
success: function (r) {
$("body").html(r);
alert("Update Completed");
},
error: function (result) { alert("error " + result.statusText) }
});
}
});
</script>
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>first time to this page [ @ViewData["firsttime"].]</p>
<p>times to the page [ @ViewData["count"].]</p>
<p>session ID [ @HttpContext.Session.Id]</p>
<br />
<p>times posted [ @ViewData["post"].]</p>
<a class="Save btn btn-outline-danger btn-sm" href="javascript:;">Save Changes</a>
</div>
<HTML>
```
Startup.cs
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDistributedMemoryCache();
services.AddSession(o =>
{
o.IdleTimeout = TimeSpan.FromMinutes(60);
o.Cookie.HttpOnly = true;
o.Cookie.IsEssential = true;
});
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
}
```
```Index.chtml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Http;
using System.Data;
namespace Grid.Pages
{
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
public void OnGet()
{
if (HttpContext.Session.GetString("Index") == null)
{
ViewData["firsttime"] = "yes";
ViewData["count"] = 1;
HttpContext.Session.SetInt32("Index", 1);
HttpContext.Session.SetInt32("Count", 1);
HttpContext.Session.SetInt32("Post", 0);
ViewData["post"] = 0;
}
else
{
ViewData["firsttime"] = "no";
int? i = HttpContext.Session.GetInt32("Count");
ViewData["count"] = i++;
ViewData["post"] = 0;
HttpContext.Session.SetInt32("Count", (int)i);
}
}
public void OnPostFred([FromBody] object bd)
{
if (HttpContext.Session.GetString("Index") == null)
{
int? i = HttpContext.Session.GetInt32("Post");
ViewData["post"] = i++;
HttpContext.Session.SetInt32("Post", (int)i);
}
else
{
ViewData["firsttime"] = "session gone";
}
}
}
}
```
Upvotes: 0
Views: 7688
Reputation: 1
I did exactly what you said. So I start the project in visual studio in debug mode. On the index page I click on the privacy page, then back to the index page. The Session remains intact. See the HTML taken from F12
````
<HTML>
<html lang="en"><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home page - Grid</title>
<link href="/lib/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/site.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.5.1.min.js" crossorigin="anonymous" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="></script>
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" href="/">Grid</a>
<button class="navbar-toggler" aria-expanded="false" aria-controls="navbarSupportedContent" aria-label="Toggle navigation" type="button" data-target=".navbar-collapse" data-toggle="collapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" href="/Privacy">Privacy</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main class="pb-3" role="main">
<script type="text/javascript">
$("body").on("click", ".Save", function (e) {
if (confirm("Do you want to Save all your changes?")) {
var bd = ["test:", "mike"];
var i = 0;
$.ajax({
type: "POST",
url: "/Index?handler=Fred",
cache: false,
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
data: JSON.stringify(bd),
contentType: "application/json; charset=utf-8",
success: function (r) {
$("body").html(r);
alert("Update Completed");
},
error: function (result) { alert("error " + result.statusText) }
});
}
});
</script>
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>first time to this page [ no.]</p>
<p>times to the page [ 3.]</p>
<p>session ID [ 33b3e934-206d-0aa8-3db4-0cee6d41a5cf]</p>
<br>
<p>times posted [ 0.]</p>
<a class="Save btn btn-outline-danger btn-sm" href="javascript:;">Save Changes</a>
</div>
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2020 - Grid - <a href="/Privacy">Privacy</a>
</div>
</footer>
<script src="/lib/jquery/dist/jquery.min.js"></script>
<script src="/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="/js/site.js?v=dLGP40S79Xnx6GqUthRF6NWvjvhQ1nOvdVSwaNcgG18"></script>
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8GWv3jmnhshAiL19koM-TGi70Yrjt9_nk_EMCmtKd31IWu5kaP9L9bTKTJSNa0M0YxwaUcmaK2pyZBJ9HDIEebyG7OtRRXZAPkWZ-Jxkj3lcmiAFTl1E3R5TOo1taZRzKJbYP-HwcNasWbPwRdv5Uds">
</body></html>
<HTML>
````
I then click on 'save changes' which does the ajax post and the session("Index") is null. So this is the problem. See the HTML after the ajax post
````
<html lang="en"><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home page - Grid</title>
<link href="/lib/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/site.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.5.1.min.js" crossorigin="anonymous" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="></script>
</head>
<body>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home page - Grid</title>
<link href="/lib/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/site.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.5.1.min.js" crossorigin="anonymous" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="></script>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" href="/">Grid</a>
<button class="navbar-toggler" aria-expanded="false" aria-controls="navbarSupportedContent" aria-label="Toggle navigation" type="button" data-target=".navbar-collapse" data-toggle="collapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" href="/Privacy">Privacy</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main class="pb-3" role="main">
<script type="text/javascript">
$("body").on("click", ".Save", function (e) {
if (confirm("Do you want to Save all your changes?")) {
var bd = ["test:", "mike"];
var i = 0;
$.ajax({
type: "POST",
url: "/Index?handler=Fred",
cache: false,
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
data: JSON.stringify(bd),
contentType: "application/json; charset=utf-8",
success: function (r) {
$("body").html(r);
alert("Update Completed");
},
error: function (result) { alert("error " + result.statusText) }
});
}
});
</script>
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>first time to this page [ session gone.]</p>
<p>times to the page [ .]</p>
<p>session ID [ 33b3e934-206d-0aa8-3db4-0cee6d41a5cf]</p>
<br>
<p>times posted [ .]</p>
<a class="Save btn btn-outline-danger btn-sm" href="javascript:;">Save Changes</a>
</div>
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2020 - Grid - <a href="/Privacy">Privacy</a>
</div>
</footer>
<script src="/lib/jquery/dist/jquery.min.js"></script>
<script src="/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="/js/site.js?v=dLGP40S79Xnx6GqUthRF6NWvjvhQ1nOvdVSwaNcgG18"></script>
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8GWv3jmnhshAiL19koM-TGilawv_ADn2Bqy2OpVOX7UV3GoyvfC_Nk8KhmRUSvic3XHPq3ID73pBHt5s_UchzAooDOM9IvyyMX2fHn-sV8_n_26OLNgvNmJrukJyQPDJg4ICpAbMdqBoRDsIsk6lXI4">
</body></html>
````
Upvotes: 0
Reputation: 471
In .Net Core, You can access the session through IHttpContextAccessor
.
To enable that, you need to add HttpContextAccessor
in your service collection in ConfigureServices
method in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
services.AddDistributedMemoryCache();
services.AddSession(o =>
{
o.IdleTimeout = TimeSpan.FromMinutes(60);
o.Cookie.HttpOnly = true;
o.Cookie.IsEssential = true;
});
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
services.AddRazorPages();
}
Now in your IndexModel
page constructor, you can inject the dependencies
private readonly IHttpContextAccessor httpContextAccessor;
public IndexModel(ILogger<IndexModel> logger,IHttpContextAccessor httpContextAccessor)
{
_logger = logger;
this.httpContextAccessor = httpContextAccessor;
}
You can Set/Get Session on any page like this
public void OnGet()
{
if (httpContextAccessor.HttpContext.Session.GetString("Index") == null)
{
ViewData["firsttime"] = "yes";
ViewData["count"] = 1;
httpContextAccessor.HttpContext.Session.SetInt32("Index", 1);
httpContextAccessor.HttpContext.Session.SetInt32("Count", 1);
httpContextAccessor.HttpContext.Session.SetInt32("Post", 0);
ViewData["post"] = 0;
}
else
{
ViewData["firsttime"] = "no";
int? i = httpContextAccessor.HttpContext.Session.GetInt32("Count");
ViewData["count"] = i++;
ViewData["post"] = 0;
httpContextAccessor.HttpContext.Session.SetInt32("Count", (int)i);
}
}
Upvotes: 1