Придумал собственное элегантное решение, так как я ничего не нашел там.
С помощью вспомогательного класса ниже, я объявлю свою модель с этим
[BindProperty]
public InputList Gender { get; set; } = new InputList(new[] { "Man", "Woman" });
[BindProperty]
public InputList Country { get; set; } = new InputList(new NameValueCollection()
{
{ "", "--Select--" },
{ "CA", "Canada" },
{ "US", "USA" },
{ "MX", "Mexico" }
});
Вставить переключатели и выпадающий список на моей странице
@foreach (var item in Model.Gender.ListItems)
{
<input type="radio" asp-for="Gender.Value" value="@item.Value" id="Gender@(item.Value)" /><label for="Gender@(item.Value)" style="padding-right:15px;"> @item.Text </label>
}
<span asp-validation-for="Gender" class="text-danger"></span>
@Html.DropDownListFor(x => x.Country.Value, Model.Country.ListItems)
<span asp-validation-for="Country" class="text-danger"></span>
И вуаля! Валидация работает как на стороне клиента, так и на стороне сервера, обеспечивая правильность объявленного значения.
Конечно, можно перевести «Мужчина» и «Женщина» в константы, и можно переместить список стран в отдельный класс, который генерирует его один раз для всего приложения.
Вот вспомогательный класс InputList.
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace EmergenceGuardian.WebsiteTools.Web
{
/// <summary>
/// Represents a list of items to display as radio buttons or drop down list that can be bound to a web page and validated.
/// </summary>
[InputListValidation]
public class InputList
{
/// <summary>
/// Initializes a new instance of InputList with specified list of items that will be used for both the value and text.
/// </summary>
/// <param name="values">A list of string values reprenting valid values.</param>
/// <param name="required">Whether this field is required.</param>
public InputList(IEnumerable<string> values, bool required = true)
{
Required = required;
foreach (var item in values)
{
ListItems.Add(new SelectListItem(item, item));
}
}
/// <summary>
/// Initializes a new instance of InputList with specified list of SelectListItem objects.
/// </summary>
/// <param name="values">A list of SelectListItem objects representing display text and valid values.</param>
/// <param name="required">Whether this field is required.</param>
public InputList(IEnumerable<SelectListItem> values, bool required = true)
{
Required = required;
ListItems.AddRange(values);
}
/// <summary>
/// Initializes a new instance of InputList with a NameValueCollection allowing quick collection initializer.
/// </summary>
/// <param name="values">The NameValueCollection containing display texts and valid values.</param>
/// <param name="required">Whether this field is required.</param>
public InputList(NameValueCollection values, bool required = true)
{
Required = required;
foreach (var key in values.AllKeys)
{
ListItems.Add(new SelectListItem(values[key], key));
}
}
/// <summary>
/// Gets or sets whether this field is required.
/// </summary>
public bool Required { get; set; }
/// <summary>
/// Gets or sets the list of display text and valid values, used for display and validation.
/// </summary>
public List<SelectListItem> ListItems { get; set; } = new List<SelectListItem>();
/// <summary>
/// Gets or sets the user input value. This value can be bound to the UI and validated by InputListValidation.
/// </summary>
public string Value { get; set; }
}
/// <summary>
/// Validates an InputList class to ensure Value is contained in ListItems.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
sealed public class InputListValidationAttribute : ValidationAttribute
{
private const string DefaultErrorMessage = "Selected value is invalid.";
private const string DefaultRequiredErrorMessage = "The {0} field is required.";
public InputListValidationAttribute()
{
}
/// <summary>
/// Validates whether InputList.Value contains a valid value.
/// </summary>
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var input = value as InputList;
if (input != null)
{
if (string.IsNullOrEmpty(input.Value))
{
if (input.Required)
{
return new ValidationResult(string.Format(ErrorMessage ?? DefaultRequiredErrorMessage, validationContext.MemberName));
}
}
else if (input.ListItems?.Any(x => x.Value == input.Value) == false)
{
return new ValidationResult(ErrorMessage ?? DefaultErrorMessage);
}
}
return ValidationResult.Success;
}
}
}