'FluentValidator and select element

I use Razor pages and want to specify a rule, when at least one selectItem should be selected for multiply select element.

I have the following rule:

public class MailRangeValidator : AbstractValidator<MailsRangeModel>
{
    public MailRangeValidator()
    {
        RuleFor(x => x.SelectedFolders)
            .Must(x => x.Count() > 0)
            //.Must(coll => coll.Any(item => !string.IsNullOrWhiteSpace(item)))
            .WithMessage("At least one folder should be selected");
    }
}

and the following strings in the Program.cs:

builder.Services.AddFluentValidation();
builder.Services.AddTransient<IValidator<MailsRangeModel>, MailRangeValidator>();

property SelectedFolders is declared as:

    [BindProperty]
    public string[] SelectedFolders { get; set; }

and the following select element:

    <select asp-for="SelectedFolders" asp-items="Model.Folders" size="10"></select>

when I don't select any element (leave select as empty), on my OnPostShowDataAsync:

    public async Task<IActionResult> OnPostShowDataAsync()
    {
        if (!ModelState.IsValid)
        {
            return new PageResult();
        }

ModelState.IsValid is true. Why and how to fix it?



Solution 1:[1]

AddFluentValidation must be called directly after calling AddMvc.

AddFluentValidation extension method inside the ConfigureServices method (which requires a using FluentValidation.AspNetCore). This method must be called directly after calling AddMvc.

builder.Services.AddMvc().AddFluentValidation();
builder.Services.AddTransient<IValidator<MailsRangeModel>, MailRangeValidator>();

Solution 2:[2]

from documentation https://docs.fluentvalidation.net/en/latest/aspnet.html:

Configuration for use with ASP.NET Razor Pages and PageModels is exactly the same as with MVC above, but with the limitation that you can’t define a validator for the whole page-model, only for models exposed as properties on the page model.

so, problem is solved by the following way:

    private List<string> Validate()
    {
        MailRangeValidator validator = new MailRangeValidator();
        var result = validator.TestValidate(this);

        return result.Errors.Select(a => a.ErrorMessage).ToList();
    }

after it we check whether Errors exists, push it to ModelState and return to client:

        var errors = Validate();
        if (errors.Count > 0)
        {
            foreach (var error in errors)
            {
                ModelState.AddModelError("", error);
            }

            await FillDataAsync();
            return Page();
        }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Okan Karadag
Solution 2 Oleg Sh