【问题标题】:ASP.NET Custom ErrorMessage for Model Enum field模型枚举字段的 ASP.NET 自定义错误消息
【发布时间】:2019-04-05 03:38:40
【问题描述】:

我正在开发一个基于 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>

以及表单发布后的输出:

【问题讨论】:

  • 枚举是一个整数。也许0是你的问题。您是否尝试将第一个枚举设置为 1?
  • @Manta 是的,我有。事实上,这就是我第一次注意到这个问题的方式。 MyEnum 是从一个选择框填充的,它最初只包含枚举中的每个元素。然后我决定去掉列表顶部的“选择一个...”选项,并将其值设置为 0。
  • 有点像你在搜索这个:stackoverflow.com/q/14381564/125981

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


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

  • 您的第二次尝试仍然无效,因为 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,但没有给出使用它进行验证的示例。相反,示例是将其用于元数据。

【讨论】:

    【解决方案2】:

    我认为您正在搜索EnumDataTypeAttribute

    [EnumDataType(typeof(MyEnum), ErrorMessage = "Select an item form the list.")]
    public MyEnum MyEnum { get; set; }
    

    【讨论】:

    • 这很有用,它似乎完全符合我的 EnumCheck 属性类所做的事情,所以我可以删除它。但是,如果我将该字段声明为public MyEnum MyEnum { get; set;},那么我会收到The value '0' is invalid 消息,而不是指定的ErrorMessage。我仍然需要将该字段声明为 int。
    • 这很奇怪,我在我的示例项目中得到了正确的验证信息,你如何准确地进行验证?
    • 正如你所拥有的那样。我已经做了一个新的灵魂/项目作为具有相同结果的最小示例。也许我需要一种不同的方法来显示错误?我都试过了:@Html.ValidationMessageFor(m =&gt; m.MyEnum)&lt;span asp-validation-for="@Model.MyEnum" class="text-danger"&gt;&lt;/span&gt;
    • 我认为这个计划永远行不通。如果发布的值无法转换为枚举,则永远无法达到 ValidationAttributes。错误发生在模型绑定的更早阶段。如果发布的值可以变成一个枚举,那么验证总是通过!无论哪种方式,这个 ValidationAttribute 永远不会返回失败。
    【解决方案3】:

    定义你的模型:

    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>
    

    【讨论】:

      猜你喜欢
      • 2018-02-08
      • 2020-07-02
      • 2011-09-14
      • 2018-03-18
      • 2011-09-23
      • 1970-01-01
      • 1970-01-01
      • 2011-09-11
      • 1970-01-01
      相关资源
      最近更新 更多