skip to Main Content

This is ASP.NET Razor Pages Project with ASP.NET Identity Registration Page (.NET 8).
Email checking (PageRemote) works fine, but only if the Email property is not a member of the Input class (automatically generated by ASP.NET Identity)

[BindProperty]
[Required]
[EmailAddress]
[Display(Name = "Email")]
[PageRemote(
    ErrorMessage = "This email is already registered",
    AdditionalFields = "__RequestVerificationToken",
    HttpMethod = "post",
    PageHandler = "CheckEmail"
    )]
public string? Email { get; set; }
public JsonResult OnPostCheckEmail()
{
    var valid = !_dbcontext.Accounts.ToList().Exists(p => p.Email.Equals(Email, StringComparison.CurrentCultureIgnoreCase));
    return new JsonResult(valid);
}

Once you put this construction in a Input class, everything stops working.

[BindProperty]
public InputModel Input { get; set; }
public class InputModel
{
    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
    [PageRemote(
        ErrorMessage = "This email is already registered",
        AdditionalFields = "__RequestVerificationToken",
        HttpMethod = "post",
        PageHandler = "CheckEmail"
        )]
    public string? Email { get; set; }
}
public JsonResult OnPostCheckEmail()
{
    var valid = !_dbcontext.Accounts.ToList().Exists(p => p.Email.Equals(Input.Email, StringComparison.CurrentCultureIgnoreCase));
    return new JsonResult(valid);
}

What am I doing wrong?)

2

Answers


  1. When you use a tag helper to generate an input for a nested class property, the name attribute is generated as NestedClassName.PropertyName All fields listed in the AdditionalFields property will be prefixed with the nested class name when they are posted, so in your case, the request verification token will be posted as Input.__RequestVerificationToken. Consequently, the request verification token itself is not found, and request verification fails resulting in a 400 status code.

    Add a separate property to the PageModel – Email – for the remote validation, as in your working example, and on successful validation, assign the value to the nested property. Or write your own JavaScript to perform remote validation.

    [BindProperty,Required,EmailAddress]
    [PageRemote(
    ErrorMessage = "This email is already registered",
    AdditionalFields = "__RequestVerificationToken",
    HttpMethod = "post",
    PageHandler = "CheckEmail"
    )] public string Email {get;set;}
    
    public async Task OnPostAsync()
    {
        if(ModelState.IsValid)
        {
            Input.Email = Email;
            //...
        }
    }
    

    In your view template:

    <input asp-for="Email" />
    
    Login or Signup to reply.
  2. Razor Pages remote validation requires the property to be validated must be a direct descendent of the PageModel class (i.e. not a property of a child property of the PageModel). And the __RequestVerificationToken is always on the root of the model.

    It will pass Input.__RequestVerificationToken to handler when [PageRemote] is declared in the InputModel, but there is no such element named Input__RequestVerificationToken, so the PageRemote request will always get http status code 400 which is why everthing stops working.

    enter image description here

    So you can write a simple script to strip out the prefix for the request verification token.

    @section Scripts {
        <script>
            $(function () {
                var remoteValidators = document.querySelectorAll('[data-val-remote-additionalfields]');
                if (remoteValidators) {
                    remoteValidators.forEach(val => {
                        var value = val.getAttribute('data-val-remote-additionalfields');
                        value = value.replace('*.__RequestVerificationToken', '__RequestVerificationToken');
                        val.setAttribute('data-val-remote-additionalfields', value);
                    });
                }
            });
        </script>
        <partial name="_ValidationScriptsPartial" />
    }
    

    NOTE: This script needs to be placed after jQuery, but before the validation libraries.

    For the handler:

    public JsonResult OnPostCheckEmail()
    {
        //you can get the email like below
        string email = Input.Email;
        // Your logic to check if email is already registered
        bool valid = true; // Replace this with your actual logic
        return new JsonResult(valid );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search