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

时间:2018-10-31 21:42:34

标签: c# enums asp.net-core-2.1 validationattribute ivalidatableobject

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

[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继承的类,要么使模型从IValidatabletableObject继承,都受此困扰。

我找到了一种解决方法:将字段声明为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类型。

是否可以为Enum字段类型提供ErrorMessage?

更新

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

型号

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>

以及表单发布后的输出:

form output

2 个答案:

答案 0 :(得分:2)

  • 在您的原始情况下,[Required(ErrorMessage = "Select an item from the list.")]设置为如果缺少MyEnum时显示的消息。但是像所有ValueTypes一样,它可能从不丢失,因此永远不会触发该验证。解决方案是可为空的ValueType。

  • 您的第二次尝试 still 不起作用,因为 model-binding 失败–“可以将空白值转换为Day吗?不,它不能。”在您的验证生效之前就加入。

Type的验证假定您要验证instance中的Type。 Aspnetcore将表单发布转换为该类型值的方法是模型绑定。如果发布的值不能与模型绑定,例如,如果将“ boo”发布到声明为int的属性中,或者将空字符串发布到Enum中,则验证甚至从未开始。而是显示 modelbinding 错误。

简单的解决方法是

  • 使用可以为空的枚举Day?,以便 modelbinding 可以成功执行空白(空白解析为null)。
  • 使用[Required()],以便使null的值无法通过验证。

结论:将表单更改为:

public class Form
{
    [Required(ErrorMessage = "Select an item from the list.")]
    public Day? Day { get; set; }
}

然后它将按您期望的那样工作。

参考:Model Validation in AspNet Core MVC

NB与其他ValidationAttributes不同,documentation for EnumDataType尽管继承自ValidationAttribute,但没有提供使用它进行验证的示例。相反,该示例是将其用于MetaData。

答案 1 :(得分:0)

我认为您正在搜索In file included from /Users/adtrevor/CompileSDL/Sources/SDL/src/video/qnx/video.c:23: /Users/adtrevor/CompileSDL/Sources/SDL/src/video/qnx/sdl_qnx.h:26:10: fatal error: 'screen/screen.h' file not found #include <screen/screen.h> ^~~~~~~~~~~~~~~~~ 1 error generated. In file included from /Users/adtrevor/CompileSDL/Sources/SDL/src/video/qnx/keyboard.c:26: /Users/adtrevor/CompileSDL/Sources/SDL/src/video/qnx/sdl_qnx.h:26:10: fatal error: 'screen/screen.h' file not found #include <screen/screen.h> ^~~~~~~~~~~~~~~~~ 1 error generated. In file included from /Users/adtrevor/CompileSDL/Sources/SDL/src/video/qnx/gl.c:23: /Users/adtrevor/CompileSDL/Sources/SDL/src/video/qnx/sdl_qnx.h:26:10: fatal error: 'screen/screen.h' file not found #include <screen/screen.h> ^~~~~~~~~~~~~~~~~ 1 error generated.

EnumDataTypeAttribute