In my Blazor application (WebAssembly), I need to load User data in my ApplicationState. Many of my pages needs this User data, so on their OnAfterRenderAsync method, I'm loading User data if it's not loaded :
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
loadingSession = true;
if (!sessionState.UserDataLoaded)
await sessionState.LoadUserData();
loadingSession = false;
}
await base.OnAfterRenderAsync(firstRender);
}
But if I go to an other page quickly, the user data won't be loaded yet, and the page will ask a new request.
So I would like to wait if there is already a request, and not to start a new one.
public async Task LoadUserData()
{
try
{
if (dataLoading)
{
// Need to wait the previous request
}
if (dataLoaded)
return;
dataLoading = true;
User = await httpClient.GetFromJsonAsync<User>("users", options);
}
catch (Exception e)
{
OnException(e);
}
finally
{
if (User != null)
dataLoaded = true;
dataLoading = false;
}
}
I tried many things, ManualResetEvent, Thread.Sleep in a Task,... but I don't manage to do it correcly. What would be the best method ?
Moving your code to the
OnInitializedAsync
method will load the user data before the control has rendered.Edit: (you want to pass state between components)
Microsoft documentation on State Management
Another example of keeping state in memory and passing it to components via Dependency Injection.
To make use of 'State management' you have to register a 'Service' that can be used for state management.
For example; Create a class named
AppState
with the values you would like to keep state of.then register this class in your
Services
asSingleton
(see Service Lifetimes):Then in your
Index.razor
file (or wherever you need to call it for the first time) use dependency injection to get access to theAppState
and in theOnInitialzedAsync()
call the user data usingHttpContent
.This will await the call to the API until it has received a response. If the response was successful ie:
response.IsSuccessStatusCode
is true. extract the data from the response message and store it in theappState.UserDate
.In any subsequent component you can get the
AppState
by injecting it using@inject AppState appState
or if it is in a code file[Inject] AppState appState;
In the subsequent components you can add a check in the
OnInitializedAsync
method :!! This is not how authentication should be handled though !!
If you need authentication look at ASP.NET Core Blazor authentication and authorization as it makes use of AuthenticationStateProvider.
In regards to checking if the call has already been made to the http client, the
await
should wait for the response from thehttpClient
before continuing.If
appState.UserData
has some value then the call was successfull..