我想基于枚举类型为验证消息添加样式。
FluentValidation 可以使用WithState
方法为邮件添加自定义状态。根据使用的枚举,它会在HTML中为该消息添加一个类,所以稍后我可以为它添加样式。
模型验证器类:
public class SampleModelValidator : AbstractValidator<SampleModelValidator>
{
public SampleModelValidator()
{
RuleFor(o => o.Age)).NotEmpty()
// Using custom state here
.WithState(o => MsgTypeEnum.WARNING)
.WithMessage("Warning: This field is optional, but better fill it!");
}
}
控制器操作方法:
[HttpPost]
public ActionResult Submit(SampleModel model)
{
ValidationResult results = this.validator.Validate(model);
int warningCount = results.Errors
.Where(o => o.CustomState?.ToString() == MsgTypeEnum.WARNING.ToString())
.Count();
...
}
我注意到ASP.NET MVC默认使用unobtrusive.js
并为每条错误消息添加了类.field-validation-error
。所以我想需要以某种方式覆盖这种逻辑。
如何根据提供的枚举类型为验证消息添加样式?
答案 0 :(得分:0)
我想出了如何实现这一点。首先需要创建一个html帮助器,它将构建html标签并为它们添加必要的类。此帮助程序允许为一个字段/属性显示具有不同类型的多个消息。
伟大的文章解释了如何做到这一点,可能是那里唯一的一个!
http://www.pearson-and-steel.co.uk/
Html Helper方法
public static MvcHtmlString ValidationMessageFluent<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression, int? itemIndex = null)
{
List<ValidationFailure> validationFailures = html.ViewData["ValidationFailures"] as List<ValidationFailure>;
string exprMemberName = ((MemberExpression)expression.Body).Member.Name;
var priorityFailures = validationFailures.Where(f => f.PropertyName.EndsWith(exprMemberName));
if (priorityFailures.Count() == 0)
{
return null;
}
// Property name in 'validationFailures' may also be stored like this 'SomeRecords[0].PropertyName'
string propertyName = itemIndex.HasValue ? $"[{itemIndex}].{exprMemberName}" : exprMemberName;
// There can be multiple messages for one property
List<TagBuilder> tags = new List<TagBuilder>();
foreach (var validationFailure in priorityFailures.ToList())
{
if (validationFailure.PropertyName.EndsWith(propertyName))
{
TagBuilder span = new TagBuilder("span");
string customState = validationFailure.CustomState?.ToString();
// Handling the message type and adding class attribute
if (string.IsNullOrEmpty(customState))
{
span.AddCssClass(string.Format("field-validation-error"));
}
else if (customState == MsgTypeEnum.WARNING.ToString())
{
span.AddCssClass(string.Format("field-validation-warning"));
}
// Adds message itself to the html element
span.SetInnerText(validationFailure.ErrorMessage);
tags.Add(span);
}
}
StringBuilder strB = new StringBuilder();
// Join all html tags togeather
foreach(var t in tags)
{
strB.Append(t.ToString());
}
return MvcHtmlString.Create(strB.ToString());
}
此外,内部控制器操作方法需要获取验证器错误并将其存储在会话中。
控制器操作方法
// In controller you also need to set the ViewData. I don't really like to use itself
// but did not found other solution
[HttpPost]
public ActionResult Submit(SampleModel model)
{
IList<ValidationFailure> errors = this.validator.Validate(model).Errors;
ViewData["ValidationFailures"] = errors as List<ValidationFailure>;
...
}
只需在视图中使用该html助手。
<强> 查看 强>
// In html view (using razor syntax)
@for (int i = 0; i < Model.SomeRecords.Count(); i++)
{
@Html.ValidationMessageFluent(o => Model.SomeRecords[i].PropertyName, i)
...
}
仅在循环列表时才需要最后一个索引参数。