4

我正在开发一个基于 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 继承的类,要么让模型都从 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 类型。

有没有办法为 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>

表单发布后的输出:

表单输出

4

3 回答 3

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

  • 您的第二次尝试仍然无效,因为模型绑定失败 - “可以将空白值转换为 aDay吗?不,它不能。” 在您的验证开始之前开始。

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

简单的解决方案是

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

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

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

然后它将按您的预期工作。

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

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

于 2018-11-24T19:04:47.227 回答
1

我认为您正在寻找EnumDataTypeAttribute

[EnumDataType(typeof(MyEnum), ErrorMessage = "Select an item form the list.")]
public MyEnum MyEnum { get; set; }
于 2018-10-31T22:44:25.277 回答
0

定义你的模型:

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>
于 2021-11-17T10:12:37.143 回答