如何在 FluentValidation 中创建警告消息
How to create warning messages in FluentValidation
我想根据枚举类型为验证消息添加样式。
FluentValidation 提供了使用 WithState
方法为消息添加自定义状态的可能性。根据使用的枚举,它会在 HTML 中为该消息添加 class,因此稍后我可以为其添加样式。
模型验证器class:
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
并在每个错误消息中添加 class .field-validation-error
。所以我想需要以某种方式覆盖该逻辑。
如何根据提供的枚举类型向验证消息添加样式?
我想出了如何实现它。首先需要创建一个 html 助手,它将构建 html 标签并向它们添加必要的 类。这个助手允许为一个 field/property 显示多个不同类型的消息。
很棒的文章,解释了如何去做,可能是唯一的一篇!
http://www.pearson-and-steel.co.uk/
Html 辅助方法
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)
...
}
只有在遍历列表时才需要最后一个索引参数。
我想根据枚举类型为验证消息添加样式。
FluentValidation 提供了使用 WithState
方法为消息添加自定义状态的可能性。根据使用的枚举,它会在 HTML 中为该消息添加 class,因此稍后我可以为其添加样式。
模型验证器class:
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
并在每个错误消息中添加 class .field-validation-error
。所以我想需要以某种方式覆盖该逻辑。
如何根据提供的枚举类型向验证消息添加样式?
我想出了如何实现它。首先需要创建一个 html 助手,它将构建 html 标签并向它们添加必要的 类。这个助手允许为一个 field/property 显示多个不同类型的消息。
很棒的文章,解释了如何去做,可能是唯一的一篇!
http://www.pearson-and-steel.co.uk/
Html 辅助方法
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)
...
}
只有在遍历列表时才需要最后一个索引参数。