'Blazor Server Storing Initial QueryParameters
Problem: Storing startup query strings for the life of the session. These startup query strings are optional parameters ("?mode=run") and do not persist between pages. I'm having a hard time finding a single entry point to set the ProtectedSessionStorage.
1. First I tried a scoped service with dependency injection. That works great until the user refreshes the page.
private RunModeSettings _rms = new RunModeSettings();
private readonly ProtectedSessionStorage _protectedSessionStore;
private readonly NavigationManager _navManager;
public RunModeService(ProtectedSessionStorage ProtectedSessionStore, NavigationManager NavManager)
{
// Constructor is called again if user refreshes the page.
// If the user is on a page that does not contain the startup query string
// then the query string is lost / overwritten with null.
_protectedSessionStore = ProtectedSessionStore;
_navManager = NavManager;
_navManager.TryGetQueryString("mode", out string mode);
// ProtectedSessionStorage is async only
// Can't check or set session storage
_rms.RunMode = mode;
}
Since ProtectedSessionStorage is alive for the lifetime of the tab I thought I could check the session storage in the service constructor to handle the refresh. Unfortunately there is no synchronous version to use in the service constructor.
2. Secondly I tried to store the query string parameters by overriding OnInitializedAsync.
// App.razor
protected override async Task OnInitializedAsync()
{
_navManager.TryGetQueryString("mode", out string mode);
if ((await _protectedSessionStore.GetAsync<RunModeSettings>("RMS")).Value == null)
await _protectedSessionStore.SetAsync("RMS", new RunModeSettings() { RunMode = mode});
}
Since we can only use ProtectedSessionStorage in asynchronous overrides it's not guaranteed that OnInitializedAsync in App.Razor component is completed before continuation. This introduces a race condition between other early components like <App>, <NavMenu> and <MainLayout>.
In asp.net I could use the Session_Start event as an entry point to store my startup query parameters for the rest of session. Is there a similar entry point in Bazor?
Solution 1:[1]
I came up with something not so elegant but it's simple and works good. I register the scoped service as usual.
builder.Services.AddScoped<RunModeService>();
The scoped services job is to maintain startup query string parameters inside an object named RunModeSettings. Upon construction of the service I use dependency injection to access the query string. I store the settings object in the session storage incase a refresh happens on a page that does not include the startup query string parameters.
To handle the race condition RunModeSettings are accessed via GetRunModeSettingsAsync. It returns the object that the service was constructed with or pulls it from the session if ready.
public class RunModeService
{
private RunModeSettings _rms = new RunModeSettings();
private readonly ProtectedSessionStorage _protectedSessionStore;
private readonly NavigationManager _navManager;
public RunModeService(ProtectedSessionStorage ProtectedSessionStore, NavigationManager NavManager)
{
_protectedSessionStore = ProtectedSessionStore;
_navManager = NavManager;
// Get optional parameters.
_navManager.TryGetQueryString("mode",out string mode);
_rms.RunMode = mode;
// Fire and forget.
SetRunModeAsync();
}
public async Task SetRunModeAsync()
{
if ((await _protectedSessionStore.GetAsync<RunModeSettings>("RMS")).Value == null)
await _protectedSessionStore.SetAsync("RMS", _rms);
}
public async Task<RunModeSettings> GetRunModeSettingsAsync()
{
return (await _protectedSessionStore.GetAsync<RunModeSettings>("RMS")).Value ?? _rms;
}
}
Now the lifetime of my settings within the service are not determined by the service scope. In my case I use ProtectedSessionStorage to keep the lifetime with the tab. Finally, we can access our service as usual.
@inject RunModeService _rms; // Page inject
[Inject] public RunModeService rms { get; set; } // Or code inject
var rms = await _rms.GetRunModeSettingsAsync();
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | clamchoda |
