I am in the process of porting an older ASP.NET 4.5 website to ASP.NET Core 3.0, and am running into some issues with the identity Razor pages and how they work.
For example, on the registration page of the application, as shown below, the form is entirely filled out, but when the button is clicked and I hit the breakpoint in the PostAsync()
method of the Register.cs
file, with the Input
model bound, everything is always null
, except for the Enum which I set the initially selected value in the HTML.
Note: Yes I see the typing in the code file. That isn't the issue. I got rid of that after I took the screenshot.
[BindProperty]
public InputModel Input { get; set; }
public class InputModel
{
[Required]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Required]
[Display(Name = "Gender")]
public Gender Gender { get; set; }
[Required]
[Phone]
[Display(Name = "MobilePhone")]
public string MobilePhone { get; set; }
[Required]
[EmailAddress]
[Display(Name = "Email")]
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; }
}
And in my Startup
file:
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressConsumesConstraintForFormFileParameters = true;
options.SuppressInferBindingSourcesForParameters = true;
options.SuppressModelStateInvalidFilter = true;
options.SuppressMapClientErrors = true;
});
Any thoughts on why the ModelState
is always invalid due the form values always being null?
Here is the HTML of the form:
<form asp-route-returnUrl="@Model.ReturnUrl"
class="form-horizontal push-50-t push-50 form-register"
method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<!-- form entry - first name -->
<div class="form-group">
<div class="col-xs-12">
<div class="form-material form-material-success">
<label asp-for="Input.FirstName"></label>
<input asp-for="Input.FirstName" type="text"
id="register-firstname" name="register-firstname"
class="form-control" placeholder="Enter your first name" />
<span asp-validation-for="Input.FirstName" class="text-danger"></span>
</div>
</div>
</div>
<!-- form entry - last name -->
<div class="form-group">
<div class="col-xs-12">
<div class="form-material form-material-success">
<label asp-for="Input.LastName"></label>
<input asp-for="Input.LastName" type="text"
id="register-lastname" name="register-lastname"
class="form-control" placeholder="Enter your last name" />
<span asp-validation-for="Input.LastName" class="text-danger"></span>
</div>
</div>
</div>
<!-- form entry - gender -->
<div class="form-group">
<div class="col-xs-12">
<div class="form-material form-material-success">
<label asp-for="Input.Gender"></label>
<select class="form-control" asp-for="Input.Gender" id="register-gender" name="register-gender"
placeholder="Please enter Male/Female">
<option selected="selected" value="@Gender.Male">Male</option>
<option value="@Gender.Female">Female</option>
</select>
<span asp-validation-for="Input.Gender" class="text-danger"></span>
</div>
</div>
</div>
<!-- form entry - mobile phone -->
<div class="form-group">
<div class="col-xs-12">
<div class="form-material form-material-success">
<label asp-for="Input.MobilePhone"></label>
<input asp-for="Input.MobilePhone" type="tel"
id="register-mobilephone" name="register-mobilephone"
class="form-control" placeholder="Provide your mobile phone number" />
<span asp-validation-for="Input.MobilePhone" class="text-danger"></span>
</div>
</div>
</div>
<!-- form entry - email -->
<div class="form-group">
<div class="col-xs-12">
<div class="form-material form-material-success">
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email"
type="email" id="register-email" name="register-email"
class="form-control" placeholder="Your email address" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
</div>
</div>
<!-- form entry - password -->
<div class="form-group">
<div class="col-xs-12">
<div class="form-material form-material-success">
<label asp-for="Input.Password"></label>
<input asp-for="Input.Password"
type="password" id="register-password" name="register-password"
class="form-control" placeholder="Choose a strong password" />
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
</div>
</div>
<!-- form entry - confirm password -->
<div class="form-group">
<div class="col-xs-12">
<div class="form-material form-material-success">
<label asp-for="Input.ConfirmPassword"></label>
<input asp-for="Input.ConfirmPassword"
type="password" id="register-password2" name="register-password2"
class="form-control" placeholder="Confirm your password" />
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div>
</div>
</div>
<div class="form-group">
<div class="col-xs-7 col-sm-8">
<label class="css-input switch switch-sm switch-success">
<input type="checkbox" id="register-terms" name="register-terms"><span></span> I agree with terms & conditions
</label>
</div>
<div class="col-xs-5 col-sm-4">
<div class="font-s13 text-right push-5-t">
<a href="#" data-toggle="modal" data-target="#modal-terms">View Terms</a>
</div>
</div>
</div>
<div class="form-group">
<div class="col-xs-12 col-sm-6 col-sm-offset-3">
<button id="register-button" class="btn btn-sm btn-block btn-success" type="submit">Create Account</button>
</div>
</div>
</form>
<!-- END Register Form -->
Update: As Requested by a commenter, here is the request payload as well.
After a few hours of laborious trail and error, the simple answer is the name attribute in the html markup HAS TO BE the model property name.
I am posting this as the answer so that any others who experience this issue can easily find the solution here.
i.e this is what was causing the failure on each property
<!-- form entry - email -->
<div class="form-group">
<div class="col-xs-12">
<div class="form-material form-material-success">
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" type="email" id="register-email" **name="register-email"**
class="form-control" placeholder="Your email address" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
</div>
</div>
The asp-for attribute helper within the input tag helper is what creates the id and name attributes so if you are using tag helpers with asp-for, you CANNOT also have put in your own name= attribute.