I want to use LocalStorage in an onPost method of my PageModel. But I have an error : "InvalidOperationException: JavaScript interop calls cannot be issued at this time. This is because the component is being statically rendered. When prerendering is enabled, JavaScript interop calls can only be performed during the OnAfterRenderAsync lifecycle method."
When I connect to my app, I want to remember the jwt in Local Storage because I connect with another API.
Login.cshtml
@page "/Login/{id:int?}"
@model MyApp.Pages.LoginModel
<body>
<div id="login">
<form action="/Login" method="post" asp-page-handler="OnPost">
<label for="username">EMail</label>
<input type="text" name="paramUsername" id="username" value="@Model.UserName">
</br>
<label for="password">Password</label>
<input type="text" name="paramPassword" id="password" type="password">
<button type="submit"> Envoyer </button>
</form>
</div>
</body>
Login.cshtml.cs
public class LoginModel : PageModel
{
[Inject] public UtilisateurService utilisateurService { get; set; }
[Inject] public AuthenticationStateProvider authStateProvider { get; set; }
public string UserName { get; set; }
public LoginModel(AuthenticationStateProvider authenticationStateProvider)
{
authStateProvider = authenticationStateProvider;
}
public async Task<IActionResult> OnPost(string paramUsername, string paramPassword)
{
var user = utilisateurService.Authenticate(paramUsername, paramPassword);
if (user != null)
{
CustomAuthenticationStateProvider custom = (CustomAuthenticationStateProvider)authStateProvider;
await custom.UpdateAuthenticationState(orqualClient); // ERROR HERE
return LocalRedirect("/index");
}
ModelState.AddModelError("Mdp", "Utilisateur ou mot de passe incorrect !");
return Page();
}
}
CustomAuthenticationStateProvider.cs
public class CustomAuthenticationStateProvider : AuthenticationStateProvider
{
private readonly Blazored.LocalStorage.ILocalStorageService _localStorage;
private ClaimsPrincipal _anonymous = new ClaimsPrincipal(new ClaimsIdentity());
private static string CLAIMS_IDENDITY_TYPE = "auth";
public CustomAuthenticationStateProvider(Blazored.LocalStorage.ILocalStorageService localStorage)
{
_localStorage = localStorage;
}
[...]
public async Task UpdateAuthenticationState(User user) {
ClaimsPrincipal claimsPrincipal;
bool hasJwt = await _localStorage.GetItemAsync<string>("account_jwt") != null; // ERROR HERE !
if (hasJwt)
await _localStorage.ClearAsync();
if (user != null && user.Jwt != "") {
await _localStorage.SetItemAsync("account_jwt", user.Jwt);
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.Email),
};
foreach (var role in user.Roles)
claims.Add(new Claim(ClaimTypes.Role, role));
var claimsIdentity = new ClaimsIdentity(claims, CLAIMS_IDENDITY_TYPE);
claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
} else {
claimsPrincipal = _anonymous;
}
NotifyAuthenticationStateChanged(Task.FromResult(
new AuthenticationState(claimsPrincipal)
));
}
}
When I click on my button, I get this error :
InvalidOperationException: JavaScript interop calls cannot be issued at this time. This is because the component is being statically rendered. When prerendering is enabled, JavaScript interop calls can only be performed during the OnAfterRenderAsync lifecycle method.
Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSRuntime.BeginInvokeJS(long asyncHandle, string identifier, string argsJson, JSCallResultType resultType, long targetInstanceId)
MyApp.Services.CustomAuthenticationStateProvider.UpdateAuthenticationState(User user) in CustomAuthentificationStateProvider.cs
var result = await _browserStorage.GetAsync<string>("account_jwt");
MyApp.Pages.LoginModel.OnPost(string paramUsername, string paramPassword) in Login.cshtml.cs
await custom.UpdateAuthenticationState(orqualClient);
I have tried to save my jwt in the local storage directly in the onPost method, but I have the same error.
Yes your are right, JavaScript interop calls can only be performed during the
OnAfterRenderAsynclifecycle method. change the code accordingly. Add a Boolean Flag and make it true inOnAfterRender