One possible approach is to imitate the legacy session variables of ASP.net webforms. These rely on a cookie without expiration date. So is the lifetime of the cookie equal to the lifetime of the browser session.
The main job is to be done in _Host.cshtml where we’ll create a guid that will serve as session identifier. This guid will be valid for the whole browser session (all tabs).
- Create this property:
public Guid NewGuid { get; } = Guid.NewGuid();
- Inject HttpContextAccessor :
public HostModel(IHttpContextAccessor httpContextAccessor)
- Get the cookie value:
string g = httpContextAccessor.HttpContext.Request.Cookies["SessionGuid"] ?? "";
if (Guid.TryParse(g, out Guid guid))
request.SessionGuid = guid;
else
request.SessionGuid = NewGuid
In this code, request is a cascading parameter that will be passed to all components.
In the markup, you add this in the body
<script>createSessionGuid('@Model.NewGuid');</script>
This use this small javascript function which have to be loaded:
function createSessionGuid(newguid) {
var current = getCookie("SessionGuid");
if ((current === null) || (current === "")) {
var guid = newguid;
document.cookie = "SessionGuid=" + guid + "; path=/";
console.log("SessionGuid created : " + guid);
}
else {
console.log("SessionGuid found : " + current);
}
}
By this way, you get a session id, without using JSInterop, thus without using any async code.
The rest of the story is quite simple: just create a sessions class, which is a dictionary of dictionaries (concurrent dictionaries). The key in the top dictionary should be the session id. The keys in the second level dictionary are just the session variable names.
Edit : How to use CascadingValue in _Host.cshtml?
In _Host.cshtml: see the last parameter.
<component type="typeof(App)" render-mode="ServerPrerendered" param-Request="Model.request" />
In the code-behind of _Host.cshtml
public BaseClasses.Request request;
public HostModel(IHttpContextAccessor httpContextAccessor)
{
request = new BaseClasses.Request();
httpContextAccessor.HttpContext.Request.Cookies.Where(kvp => kvp.Key != "SessionGuid").ToList().ForEach(kvp => request.Cookies.Add(kvp.Key, kvp.Value));
string g = httpContextAccessor.HttpContext.Request.Cookies["SessionGuid"] ?? "";
if (Guid.TryParse(g, out Guid guid))
request.SessionGuid = guid;
else
request.SessionGuid = NewGuid;
}
This info is retrieved in MainLayout.razor.cs and starts cascading there.
[CascadingParameter]
private BaseClasses.Request Request { get; set; }