模型枚举字段的 ASP.NET 自定义 ErrorMessage

Mat*_*zer 5 c# enums validationattribute ivalidatableobject asp.net-core-2.1

我正在开发一个基于 EntityFrameworkCore 并针对 ASP.NET Core 2.1 的网站。我想为模型中的枚举字段指定错误消息,如下所示:

\n\n
[Required(ErrorMessage = "Select an item from the list.")]\npublic MyEnum MyEnum { get; set; }\n
Run Code Online (Sandbox Code Playgroud)\n\n

但是,仍然生成库存消息:The value \'0\' is invalid。问题似乎是在评估我的任何代码之前验证枚举类型。这里介绍的两种方法(https://www.codeproject.com/Articles/1204077/ASP-NET-Core-MVC-Model-Validation),要么创建一个继承自 ValidationAttribute 的类,要么让模型继承自 IValidatableObject受此之苦。

\n\n

我找到了一个解决方法:将字段声明为 int,然后使用自定义验证属性:

\n\n
[EnumCheck(typeof(MyEnum), ErrorMessage = "Select an item form the list.")]\npublic int MyEnum { get; set; }\n
Run Code Online (Sandbox Code Playgroud)\n\n

...然后从 ValidationAttribute 继承子类:

\n\n
sealed public class EnumCheck : ValidationAttribute\n{\n    readonly Type t_;\n\n    public EnumCheck(Type t)\n    {\n        t_ = t;\n    }\n\n    public override bool IsValid(object value)\n    {\n        return Enum.IsDefined(t_, value);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这种方法有一些缺点,因为现在我需要在许多使用它的地方将字段转换为 Enum 类型。

\n\n

有没有办法为 Enum 字段类型提供 ErrorMessage?

\n\n

更新

\n\n

以下是一个最小的示例(不再使用 ValidationAttribute 中的 EnumCheck 子类,而是使用 @P\xc3\xa9terCsajtai 提到的 EnumDataType):

\n\n

型号\n

\n\n
namespace web.Models\n{\n    public enum Day\n    {\n        Sunday = 1,\n        Monday,\n        Tuesday,\n        Wednesday,\n        Thursday,\n        Friday,\n        Saturday\n    }\n\n    public class Form\n    {\n        [EnumDataType(typeof(Day), ErrorMessage = "Select an item from the list.")]\n        public Day Day { get; set; }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

控制器\n

\n\n
namespace web.Controllers\n{\n    public class HomeController : Controller\n    {\n        public IActionResult Index()\n        {\n            return View();\n        }\n\n        public IActionResult Save(Form model)\n        {\n            if(!ModelState.IsValid)\n            {\n                return View("Index");\n            }\n\n            return View("Index", model);\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

查看\n

\n\n
<form asp-controller="Home">\n    <div asp-validation-summary="All" class="text-danger"></div>\n    <fieldset>\n        <label asp-for="@Model.Day"></label>\n        <select asp-for="@Model.Day" asp-items="Html.GetEnumSelectList<Day>()">\n            <option value="">Select...</option>\n        </select>\n        @Html.ValidationMessageFor(m => m.Day)\n        <span asp-validation-for="@Model.Day" class="text-danger"></span>\n    </fieldset>\n    <fieldset>\n        <input type="submit" asp-action="Save" />\n    </fieldset>\n</form>\n
Run Code Online (Sandbox Code Playgroud)\n\n

以及表单发布后的输出:

\n\n

表格输出

\n

Chr*_*oll 3

    \n
  • 在您原来的情况下,[Required(ErrorMessage = "Select an item from the list.")]您正在设置消息丢失时显示的消息MyEnum。但与所有 ValueType 一样,它永远不会丢失,因此它永远不会触发该验证。解决方案是可以为 null 的 ValueType。

    \n
  • \n
  • 您的第二次努力仍然不起作用,因为模型绑定失败 \xe2\x80\x93 “可以将空白值转换为 吗Day?不,它不能。” 在您的验证开始之前就开始。

    \n
  • \n
\n

验证的前提Type是您有一个instanceType验证的。Aspnetcore 将表单帖子转换为键入的值的方式是模型绑定。如果发布的值不能是模型绑定的——例如,如果您将“boo”发布到声明为 an 的属性int,或者将空字符串发布到 an——Enum那么验证甚至永远不会开始。相反,会显示模型绑定错误。

\n

简单的解决方案是

\n
    \n
  • 使用可为 null 的 enumDay?以便 模型绑定空白成功(空白解析为null)。
  • \n
  • 使用[Required()]null值会使验证失败。
  • \n
\n

结论:将您的表格更改为:

\n
public class Form\n{\n    [Required(ErrorMessage = "Select an item from the list.")]\n    public Day? Day { get; set; }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

然后它就会按照您的预期工作。

\n

参考:AspNet Core MVC 中的模型验证

\n

注意,与其他 不同ValidationAttributes, 的文档EnumDataType虽然继承自 ValidationAttribute,但没有给出使用它进行验证的示例。相反,该示例是将其用于元数据。

\n