ASP.NET Custom ErrorMessage для поля Enum модели
Я занимаюсь разработкой веб-сайта, основанного на EntityFrameworkCore, и нацеленного на ASP.NET Core 2.1. Я хочу указать сообщение об ошибке для поля enum в моей модели следующим образом:
[Required(ErrorMessage = "Select an item from the list.")]
public MyEnum MyEnum { get; set; }
Тем не менее, фондовое сообщение все еще генерируется: The value '0' is invalid
, Кажется, проблема в том, что тип Enum проверяется до того, как будет проверен любой мой код. Два представленных здесь подхода ( https://www.codeproject.com/Articles/1204077/ASP-NET-Core-MVC-Model-Validation), либо создание класса, который наследуется от ValidationAttribute, либо наличие модели, наследуемой от IValidatableObject, страдать от этого.
Я нашел обходной путь: объявить поле как int, а затем использовать пользовательский атрибут проверки:
[EnumCheck(typeof(MyEnum), ErrorMessage = "Select an item form the list.")]
public int MyEnum { get; set; }
... а затем подкласс от ValidationAttribute:
sealed public class EnumCheck : ValidationAttribute
{
readonly Type t_;
public EnumCheck(Type t)
{
t_ = t;
}
public override bool IsValid(object value)
{
return Enum.IsDefined(t_, value);
}
}
У этого подхода есть некоторые недостатки, так как теперь мне нужно привести поле к типу Enum во многих местах, где оно используется.
Есть ли способ предоставить ErrorMessage для типов полей Enum?
ОБНОВИТЬ
Ниже приведен минимальный пример (больше не используется подкласс EnumCheck из ValidationAttribute, а скорее EnumDataType, упомянутый @PéterCsajtai):
модель
namespace web.Models
{
public enum Day
{
Sunday = 1,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
public class Form
{
[EnumDataType(typeof(Day), ErrorMessage = "Select an item from the list.")]
public Day Day { get; set; }
}
}
контроллер
namespace web.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult Save(Form model)
{
if(!ModelState.IsValid)
{
return View("Index");
}
return View("Index", model);
}
}
}
Посмотреть
<form asp-controller="Home">
<div asp-validation-summary="All" class="text-danger"></div>
<fieldset>
<label asp-for="@Model.Day"></label>
<select asp-for="@Model.Day" asp-items="Html.GetEnumSelectList<Day>()">
<option value="">Select...</option>
</select>
@Html.ValidationMessageFor(m => m.Day)
<span asp-validation-for="@Model.Day" class="text-danger"></span>
</fieldset>
<fieldset>
<input type="submit" asp-action="Save" />
</fieldset>
</form>
И вывод после формы сообщения:
3 ответа
В вашем оригинальном случае,
[Required(ErrorMessage = "Select an item from the list.")]
вы устанавливаете сообщение, которое будет отображаться, еслиMyEnum
пропал, отсутствует. Но, как и всеValueTypes
, он никогда не будет отсутствовать и никогда не будет вызывать эту проверку. Решением для этого является обнуляемый ValueType.Ваше второе усилие по- прежнему не работает, потому что ошибка привязки модели - "Можно ли преобразовать пустое значение в
Day
? Нет, не может. ", Прежде чем ваша проверка может вступить в силу.
Проверка для Type
предполагает, что у вас есть instance
того, что Type
проверить. Способ, которым Aspnetcore превращает сообщение формы в это типизированное значение, является привязкой к модели. Если опубликованное значение не может быть привязано к модели - например, если вы публикуете "boo" для свойства, объявленного как int
или пустая строка для Enum
- тогда валидация даже не начинается. Вместо этого отображается ошибка привязки модели.
Простое решение
- Используйте обнуляемое перечисление,
Day?
так что связывание модели с пробелом завершается успешно (пробел разрешается вnull
). - использование
[Required()]
так что этоnull
Значение затем не проходит проверку.
Вывод: измените свою форму на:
public class Form
{
[Required(ErrorMessage = "Select an item from the list.")]
public Day? Day { get; set; }
}
И тогда это работает.
Ссылка: Проверка модели в AspNet Core MVC
NB в отличие от других ValidationAttributes
Документация для EnumDataType
, хотя он наследует от ValidationAttribute, не дает пример использования его для проверки. Вместо этого пример использования его для метаданных.
Я думаю, что вы ищете EnumDataTypeAttribute
:
[EnumDataType(typeof(MyEnum), ErrorMessage = "Select an item form the list.")]
public MyEnum MyEnum { get; set; }
Определите свою модель:
public enum Day
{
None=0,
Sunday = 1,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
а затем определите свой пользовательский атрибут проверки:
sealed public class EnumCheck : ValidationAttribute
{
readonly Type t_;
public EnumCheck(Type t)
{
t_ = t;
}
public override bool IsValid(object value)
{
if (((int)value)==0)
{
return false;
}
return Enum.IsDefined(t_, value);
}
}
и, наконец, используйте это, на ваш взгляд:
<form asp-controller="Home">
<div asp-validation-summary="All" class="text-danger"></div>
<fieldset>
<label asp-for="@Model.Day"></label>
<select asp-for="@Model.Day" asp-items="Html.GetEnumSelectList<Day>()">
<option value="0">Select...</option>
</select>
@Html.ValidationMessageFor(m => m.Day)
<span asp-validation-for="@Model.Day" class="text-danger"></span>
</fieldset>
<fieldset>
<input type="submit" asp-action="Save" />
</fieldset>