I am developing a website built on EntityFrameworkCore and targeting ASP.NET Core 2.1. I want to specify an error message for an enum field in my model like so:
[Required(ErrorMessage = "Select an item from the list.")]
public MyEnum MyEnum { get; set; }
However, the stock message is still generated: The value '0' is invalid
. The problem appears to be that the Enum type is validated prior to any of my code being evaluated. The two approaches presented here (https://www.codeproject.com/Articles/1204077/ASP-NET-Core-MVC-Model-Validation), either creating a class that inherits from ValidationAttribute, or having the model inherit from IValidatableObject both suffer from this.
I have found a workaround: declare the field as an int, and then use a custom validation attribute:
[EnumCheck(typeof(MyEnum), ErrorMessage = "Select an item form the list.")]
public int MyEnum { get; set; }
...and then subclass from 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);
}
}
This approach has some drawbacks as now I need to cast the field to the Enum type in many places that it is used.
Is there a way to provide an ErrorMessage for Enum field types?
UPDATE
The following is a minimal example (No longer using EnumCheck subclass from ValidationAttribute, but rather the EnumDataType mentioned by @PéterCsajtai):
Model
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; }
}
}
Controller
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);
}
}
}
View
<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>
And the output after form post: