整体设计
首先,我相信如果用户选择忽略警告,您将不得不以某种方式进行跟踪。一种简单而透明的方法是设置一个忽略警告复选框,用户必须在提交之前检查该复选框。另一种选择是让他们提交表单两次并忽略第二次提交时的警告;那么你可能需要一个IgnoreWarnings隐藏字段。可能还有其他设计,但为了简单起见,我将使用第一个选项。
简而言之,方法是创建
- 支持警告类型验证的所有视图模型的自定义数据注释属性;
- 视图模型将从其继承的已知基类;
- 我们必须为每个自定义属性复制 JavaScript 中的逻辑。
请注意,下面的代码只是说明了这种方法,我必须在不知道完整上下文的情况下假设很多事情。
查看模型
在这种情况下,最好将视图模型与实际模型分开,这无论如何都是个好主意。一种可能的方法是为所有支持警告的视图模型创建一个基类:
public abstract class BaseViewModel
{
public bool IgnoreWarnings { get; set; }
}
模型需要分开的关键原因是将IgnoreWarnings
属性存储在数据库中几乎没有意义。
您的派生视图模型将如下所示:
public class YourViewModel : BaseViewModel
{
[Required]
[StringLengthWarning(MaximumLength = 5, ErrorMessage = "Your Warning Message")]
public string YourProperty { get; set; }
}
StringLengthWarning
是用于服务器和客户端验证的自定义数据注释属性。它只支持最大长度,并且可以使用任何其他必要的属性轻松扩展。
数据注释属性
属性的核心是IsValid(value, validationContext
方法。
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class StringLengthWarningAttribute : ValidationAttribute, IClientValidatable
{
public int MaximumLength { get; set; }
public override bool IsValid(object value)
{
return true;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var model = validationContext.ObjectInstance as BaseViewModel;
var str = value as string;
if (!model.IgnoreWarnings && (string.IsNullOrWhiteSpace(str) || str.Length > MaximumLength))
return new ValidationResult(ErrorMessage);
return base.IsValid(value, validationContext);
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new StringLengthWarningValidationRule(MaximumLength, ErrorMessage);
}
}
该属性实现IClientValidatable
并利用自定义客户端验证规则:
public class StringLengthWarningValidationRule : ModelClientValidationRule
{
public StringLengthWarningValidationRule(int maximumLength, string errorMessage)
{
ErrorMessage = errorMessage;
ValidationType = "stringlengthwarning";
ValidationParameters.Add("maximumlength", maximumLength);
ValidationParameters.Add("ignorewarningsfield", "IgnoreWarnings");
}
}
客户端 JavaScript
最后,要使其工作,您需要从您的视图中引用以下 JavaScript:
$(function () {
$.validator.addMethod('stringlengthwarning', function (value, element, params) {
var maximumlength = params['maximumlength'];
var ignorewarningsfield = params['ignorewarningsfield'];
var ctl = $("#" + ignorewarningsfield);
if (ctl == null || ctl.is(':checked'))
return true;
return value.length <= maximumlength;
});
$.validator.unobtrusive.adapters.add("stringlengthwarning", ["maximumlength", "ignorewarningsfield"], function (options) {
var value = {
maximumlength: options.params.maximumlength,
ignorewarningsfield: options.params.ignorewarningsfield
};
options.rules["stringlengthwarning"] = value;
if (options.message) {
options.messages["stringlengthwarning"] = options.message;
}
});
}(jQuery));
JavaScript 做了一些您可能想要重新访问的假设(复选框名称等)。
更新:HTML 助手
要分别显示错误和警告的验证消息,需要几个帮助程序。下面的类提供了一个示例:
public static class MessageHelpers
{
public static MvcHtmlString WarningMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
if (htmlHelper.ViewData.ModelState["IgnoreWarnings"] != null)
return htmlHelper.ValidationMessageFor(expression);
return MvcHtmlString.Empty;
}
public static MvcHtmlString ErrorMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
if (htmlHelper.ViewData.ModelState["IgnoreWarnings"] == null)
return htmlHelper.ValidationMessageFor(expression);
return MvcHtmlString.Empty;
}
}
在视图中,它们可以照常使用:
@Html.EditorFor(model => model.YourProperty)
@Html.ErrorMessageFor(model => model.YourProperty)
@Html.WarningMessageFor(model => model.YourProperty)