Search code examples
c#asp.net-coreasp.net-core-mvcmodel-validation

Required string attribute with null value gives IsValid=true in ASP.NET Core 2 Razor Page


I'm really confused by this. I have a Razor Page on ASP.NET Core 2 that has a required property called SchemaId. I've tried marking it as [Required], [BindRequired], and [Required(AllowEmptyStrings = false)], yet when I post my form, I see that SchemaId is null and yet ModelState.IsValid == true. Here's the Upload.cshtml.cs:

namespace Uploader.Pages
{
    public class UploadModel : PageModel
    {
        private IUploader _uploader;

        public UploadModel(IUploader uploader)
        {
            _uploader = uploader;
        }

        [BindProperty]
        public IEnumerable<IFormFile> UploadedFiles { get; set; }

        [Required(AllowEmptyStrings = false)]
        [BindProperty]
        [BindRequired]
        public string SchemaId { get; set; }


        public void OnGet(string schemaId = null)
        {
            SchemaId = schemaId;
        }

        public async Task<IActionResult> OnPostAsync()
        {
            // SchemaId is NULL right here!
            if (!ModelState.IsValid) // Yet IsValid = true!
            {
                return Page();
            }

            // Use _uploader to actually upload the file

            return RedirectToPage("/Next", new { uploadId = uploadId, schemaId = SchemaId });
        }
    }
}

Relevant extract from Upload.cshtml file:

<div asp-validation-summary="All"></div>
<form enctype="multipart/form-data" method="POST" asp-page="Upload">
    <input class="inputfile" type="file" id="UploadedFiles" multiple="multiple" name="UploadedFiles">
    <label for="UploadedFiles">
        <span>Choose a file...</span>
    </label>
    <input type="hidden" asp-for="SchemaId">
    <button type="submit" class="inputfilesubmit">Upload</button>
</form>

How can I get the model validation to work properly?


Solution

  • I think I found out the reason.

    [BindRequired] and [Required] attributes defined in PageModel are seemed to be ignored. Therefore you need to validate the model something like the following:

    public class Schema
    {
        [Required]
        [BindRequired]
        public string Id { get; set; }
    }
    public class TestModel : PageModel
    {
        [BindProperty]
        public Schema Schema { get; set; }
    
        public async Task<IActionResult> OnPostAsync()
        {
            // SchemaId is NULL right here!
            if (!ModelState.IsValid) // Yet IsValid = true!
            {
                return Page();
            }
    
            return Page();
        }
    
    }
    

    Then in cshtml

    <div asp-validation-summary="All"></div>
    <form enctype="multipart/form-data" method="POST" asp-page="Upload">
        <input class="inputfile" type="file" id="UploadedFiles" multiple="multiple" name="UploadedFiles">
        <label for="UploadedFiles">
            <span>Choose a file...</span>
        </label>
        <input type="hidden" asp-for="Schema.Id">
        <button type="submit" class="inputfilesubmit">Upload</button>
    </form>
    

    I still haven't found any documentation mentioning this, but in Microsoft documentation they also write validation attributes in a separate class, so I think this behavior is expected.

    Hope this will solve the problem.