I’m using the .net 8 scaffolded blazor identity pages in a ‘Web App’ with Auto enabled.
I’ve added a to the form with hardcoded values with an int Id bound to the selected value.
However when the form is submitted this value is always zero.
ChatGPT has no answers and from what I’ve found online this should work.
Why is it always zero?
Thanks
@page "/Account/Register"
@using System.ComponentModel.DataAnnotations
@using System.Text
@using System.Text.Encodings.Web
@using Microsoft.AspNetCore.Identity
@using Microsoft.AspNetCore.WebUtilities
@using FootballHeadz3.Data
@inject UserManager<ApplicationUser> UserManager
@inject IUserStore<ApplicationUser> UserStore
@inject SignInManager<ApplicationUser> SignInManager
@inject IEmailSender<ApplicationUser> EmailSender
@inject ILogger<Register> Logger
@inject NavigationManager NavigationManager
@inject IdentityRedirectManager RedirectManager
@inject IUserRepository _userRepository
@* @rendermode InteractiveServer *@
<PageTitle>Register</PageTitle>
<h1>Register</h1>
@if (!String.IsNullOrEmpty(@Messagex))
{
<div class="alert alert-success" role="alert">
@Messagex
</div>
}
@if (!String.IsNullOrEmpty(@MessageErrorx))
{
<div class="alert alert-danger" role="alert">
@MessageErrorx
</div>
}
<div class="row">
<div class="col-md-8">
<StatusMessage Message="@Message" />
<EditForm Model="Input" asp-route-returnUrl="@ReturnUrl" method="post" OnValidSubmit="RegisterUser" FormName="register">
<DataAnnotationsValidator />
<ValidationSummary class="text-danger" role="alert" />
<div class="form-floating mb-3">
<InputText @bind-Value="Input.Email" class="form-control" autocomplete="username" aria-required="true" placeholder="[email protected]" />
<label for="email">Email</label>
<ValidationMessage For="() => Input.Email" class="text-danger" />
</div>
<div class="form-floating mb-3">
<InputText @bind-Value="Input.FHUsername" class="form-control" aria-required="true" placeholder="[email protected]" />
<label for="fhusername">Username (publicly visible, not email)</label>
<ValidationMessage For="() => Input.FHUsername" class="text-danger" />
</div>
<div class="form-floating mb-3">
<InputText maxlength="50" @bind-Value="Input.HowHearText" class="form-control" aria-required="true" placeholder="[email protected]" />
<label for="fhusername">How did you hear about us?</label>
<ValidationMessage For="() => Input.HowHearText" class="text-danger" />
</div>
@* this wont bind for some reason, just using a textbox *@
<div class="form-floating mb-3">
<select @bind="@Input.HowHearId" id="() => Input.HowHearId" class="form-select">
<option value="0">Please Select...</option>
<option value="1">Google</option>
<option value="2">YouTube</option>
<option value="3">Word of Mouth</option>
<option value="4">FPL Black Box</option>
<option value="100">Other</option>
</select>
<label for="howhearid">How did you hear about us?</label>
<ValidationMessage For="() => Input.HowHearId" class="text-danger" />
</div>
<div class="form-floating mb-3">
<InputText @bind-Value="Input.TeamSupported" class="form-control" aria-required="true" placeholder="[email protected]" />
<label for="teamsupported">Team Supported</label>
<ValidationMessage For="() => Input.TeamSupported" class="text-danger" />
</div>
<div class="form-floating mb-3">
<InputText @bind-Value="Input.Country" class="form-control" aria-required="true" placeholder="[email protected]" />
<label for="country">Country</label>
<ValidationMessage For="() => Input.Country" class="text-danger" />
</div>
<div class="form-floating mb-3">
<InputText @bind-Value="Input.XUsername" class="form-control" aria-required="true" placeholder="[email protected]" />
<label for="xusername">X/Twitter Username</label>
<ValidationMessage For="() => Input.XUsername" class="text-danger" />
</div>
<div class="form-floating mb-3">
<InputText type="password" @bind-Value="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" placeholder="password" />
<label for="password">Password</label>
<ValidationMessage For="() => Input.Password" class="text-danger" />
</div>
@* <div class="form-floating mb-3">
<InputText type="password" @bind-Value="Input.HowHearId" class="form-control" autocomplete="new-password" aria-required="true" placeholder="password" />
<label for="confirm-password">How did you hear about us?</label>
<ValidationMessage For="() => Input.HowHearId" class="text-danger" />
</div> *@
<div class="form-floating mb-3">
<InputText type="password" @bind-Value="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" placeholder="password" />
<label for="confirm-password">Confirm Password</label>
<ValidationMessage For="() => Input.ConfirmPassword" class="text-danger" />
</div>
<button type="submit" class="w-100 btn btn-lg btn-primary">Register</button>
</EditForm>
</div>
@* <div class="col-md-6 col-md-offset-2">
<section>
<h3>Use another service to register.</h3>
<hr />
<ExternalLoginPicker />
</section>
</div> *@
</div>
@code {
public string? Messagex { get; set; }
public string? MessageErrorx { get; set; }
private IEnumerable<IdentityError>? identityErrors;
[SupplyParameterFromForm]
//private InputModel Input { get; set; }
private InputModel Input { get; set; } = new();
public int _howHearId { get; set; }
[SupplyParameterFromQuery]
private string? ReturnUrl { get; set; }
private string? Message => identityErrors is null ? null : $"Error: {string.Join(", ", identityErrors.Select(error => error.Description))}";
public async Task RegisterUser(EditContext editContext)
{
if (await _userRepository.FHUsernameExistsAsync(Input.FHUsername))
{
MessageErrorx = "Username already exists, please choose another";
return;
}
var user = CreateUser();
// Map additional fields
user.TeamSupported = Input.TeamSupported;
user.Country = Input.Country;
user.FHUsername = Input.FHUsername;
user.XUsername = Input.XUsername;
user.HowHearText = Input.HowHearText;
user.DateJoined = DateTime.Now;
//user.HowHearId = Input.HowHearId;
await UserStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
var emailStore = GetEmailStore();
await emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
var result = await UserManager.CreateAsync(user, Input.Password);
if (!result.Succeeded)
{
identityErrors = result.Errors;
return;
}
//Logger.LogInformation("User created a new account with password.");
var userId = await UserManager.GetUserIdAsync(user);
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = NavigationManager.GetUriWithQueryParameters(
NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri,
new Dictionary<string, object?> { ["userId"] = userId, ["code"] = code, ["returnUrl"] = ReturnUrl });
await EmailSender.SendConfirmationLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl));
if (UserManager.Options.SignIn.RequireConfirmedAccount)
{
RedirectManager.RedirectTo(
"Account/RegisterConfirmation",
new() { ["email"] = Input.Email, ["returnUrl"] = ReturnUrl });
}
await SignInManager.SignInAsync(user, isPersistent: false);
RedirectManager.RedirectTo(ReturnUrl);
}
private ApplicationUser CreateUser()
{
try
{
return Activator.CreateInstance<ApplicationUser>();
}
catch
{
throw new InvalidOperationException($"Can't create an instance of '{nameof(ApplicationUser)}'. " +
$"Ensure that '{nameof(ApplicationUser)}' is not an abstract class and has a parameterless constructor.");
}
}
private IUserEmailStore<ApplicationUser> GetEmailStore()
{
if (!UserManager.SupportsUserEmail)
{
throw new NotSupportedException("The default UI requires a user store with email support.");
}
return (IUserEmailStore<ApplicationUser>)UserStore;
}
private sealed class InputModel
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
public string Email { get; set; } = "";
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; } = "";
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; } = "";
[Required(ErrorMessage = "Team Supported Required")]
[StringLength(50, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 3)]
[Display(Name = "Team Supported")]
public string? TeamSupported { get; set; }
[Required(ErrorMessage = "Country Required")]
[StringLength(60, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 2)]
public string? Country { get; set; }
[Required]
[Display(Name = "Username")]
[StringLength(20, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 2)]
public string? FHUsername { get; set; } // Used for leaderboard not login
[Display(Name = "X/Twitter Username")]
[StringLength(15, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 0)]
public string? XUsername { get; set; }
[Display(Name = "How did you hear about us?")]
[StringLength(50, ErrorMessage = "Max length of how did you hear about us 50 characters")]
public string HowHearText { get; set; }
// id wont bind just using free text
[Display(Name = "How did you hear about us?")]
//[Range(0, 100, ErrorMessage = "Please select How did you hear about us")]
public int HowHearId { get; set; }
}
}
2
Answers
You should put
name
attribute so blazor can match the form field with Model’s property.This is "automatic" when you use
<InputSelect>
component, which I would recommend.Aside from the comment:
For showing an input when "other" is selected you have to use an interactivity. You don’t need any code to run, you just check the value of
HowHearId
and based on that you change style (or you can do it withif
, but style change is one-liner). But if you really want to execute some code@bind:after
is the way to go.Full, but simplified code:
Answer of @Alamakanambra is wrong becouse you cannot change renderMode to
@rendermode InteractiveServer for scaffolded identity.
That`s a reason why you get error with cookie.
In your app.razor, purpose blazor sets all account`s page for normal render:
And you cannot change this. Becouse this makes problem with identity.
I have the same problem like you with select and for me workaround was that i write javaScript code for my select case and i call this when select is onchange.