I am new to Blazor and creating a login form for user authorization. I am using Custom authentication using my user database. I have learnt that I cannot use InteractiveServer rendermode on the login page as I need to use the HttpContext.SignInAsync method to register the claim.
Having done that, I’m unable to figure out how do I disable to login button or show a loader once the button is clicked until I get the authentication done?
Below is my login razor page code
@page "/login"
@layout Layout.MainLayout
@attribute [AllowAnonymous]
@inject ILoggingService LoggingService
@inject IUserService UserService
@inject NavigationManager NavigationManager
<div class="card">
<div class="card-body p-4">
<div class="text-center w-75 mx-auto auth-logo mb-4">
<NavLink class="logo-dark" href="">
<span><img src="assets/images/logo-dark.png" alt="" height="22"></span>
</NavLink>
</div>
@if (!string.IsNullOrWhiteSpace(ErrorMessage))
{
<div class="alert alert-danger fade show" role="alert">
<i class="mdi mdi-block-helper me-2"></i>
@ErrorMessage
</div>
}
<EditForm FormName="LoginForm" Model="@Model" OnValidSubmit="Submit" Enhance novalidate>
<DataAnnotationsValidator />
<div class="form-group mb-3">
<label for="email" class="form-label">Your Email</label>
<InputText @bind-Value="Model.EmailAddress" class="form-control" id="email" type="email" maxlength="50" required />
<ValidationMessage For="@(() => Model.EmailAddress)" class="invalid-feedback" />
</div>
<div class="form-group mb-3">
<label for="password" class="form-label">Your Password</label>
<InputText @bind-Value="Model.Password" class="form-control" id="password" type="password" maxlength="30" required />
<ValidationMessage For="@(() => Model.Password)" class="invalid-feedback" />
</div>
<button class="btn btn-primary w-100" type="submit">Login</button>
</EditForm>
</div> <!-- end card-body -->
</div>
<!-- end card -->
<div class="row mt-3">
<div class="col-12 text-center">
<p class="text-white-50">
<NavLink href="/forgot-password" class="text-white-50 ms-1">Forgot your password?</NavLink>
</p>
<p class="text-white-50">
Don't have an account? <NavLink href="/register" class="text-white font-weight-medium ms-1">Register</NavLink>
</p>
</div> <!-- end col -->
</div>
<!-- end row -->
@code {
[CascadingParameter]
private HttpContext? HttpContext { get; set; }
[SupplyParameterFromForm]
private LoginRequest Model { get; set; } = new();
private string? ErrorMessage { get; set; }
protected async Task Submit()
{
LoggingService.LogDebug("Login form submitted");
try
{
var response = await UserService.LoginAsync(Model!);
if (!response.Success)
{
LoggingService.LogDebug("Login failed using Model: {@Model}", Model);
// Show error
ErrorMessage = response.ErrorMessage;
}
else
{
var claims = new List<Claim>
{
new (ClaimTypes.Name, response.UserName!),
new (ClaimTypes.Role, response.Role)
};
var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(identity);
await HttpContext!.SignInAsync(principal);
NavigationManager.NavigateTo("", true);
}
}
finally
{
Model.Password = null!;
}
}
}
I tried to use IJSRuntime.InvokeVoidAsync inside the Submit method to call a Javascript function to show the loader but that throws an error: 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.
Murtaza is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.