我一直在与 Jeremy Skinner(Fluent Validation 的创建者)在
http://fluentvalidation.codeplex.com/discussions/253505讨论如何做到这一点
他很友善地写了一个完整的例子。
更新
这是我们提出的代码:
首先是 Match 和 NotMatch 的扩展。
public static class Extensions
{
public static IRuleBuilderOptions<T, string> Match<T>(this IRuleBuilder<T, string> ruleBuilder, string expression)
{
return ruleBuilder.SetValidator(new MatchValidator(expression));
}
public static IRuleBuilderOptions<T, string> NotMatch<T>(this IRuleBuilder<T, string> ruleBuilder, string expression) {
return ruleBuilder.SetValidator(new MatchValidator(expression, false));
}
}
验证器使用的接口
public interface IMatchValidator : IPropertyValidator
{
string Expression { get; }
bool MustMatch { get; }
}
实际验证者:
public class MatchValidator : PropertyValidator, IMatchValidator
{
string expression;
bool mustMatch;
public MatchValidator(string expression, bool mustMatch = true)
: base(string.Format("The value {0} match with the given expression, while it {1}.", mustMatch ? "did not" : "did", mustMatch ? "should" : "should not"))
{
this.expression = expression;
this.mustMatch = mustMatch;
}
protected override bool IsValid(PropertyValidatorContext context)
{
return context.PropertyValue == null ||
context.PropertyValue.ToString() == string.Empty ||
Regex.IsMatch(context.PropertyValue.ToString(), expression) == mustMatch;
}
public string Expression
{
get { return expression; }
}
public bool MustMatch {
get { return mustMatch; }
}
}
注册验证器的适配器:
public class MatchValidatorAdaptor : FluentValidationPropertyValidator
{
public MatchValidatorAdaptor(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule rule, IPropertyValidator validator)
: base(metadata, controllerContext, rule, validator)
{
}
IMatchValidator MatchValidator
{
get { return (IMatchValidator)Validator; }
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
var formatter = new MessageFormatter().AppendPropertyName(Rule.PropertyDescription);
string errorMessage = formatter.BuildMessage(Validator.ErrorMessageSource.GetString());
yield return new ModelClientValidationMatchRule(MatchValidator.Expression, MatchValidator.MustMatch, errorMessage);
}
}
最后是魔法发生的地方:
public class ModelClientValidationMatchRule : ModelClientValidationRule
{
public ModelClientValidationMatchRule(string expression, bool mustMatch, string errorMessage)
{
if (mustMatch)
base.ValidationType = "match";
else
base.ValidationType = "notmatch";
base.ValidationType += StringFunctions.RandomLetters(6);
base.ErrorMessage = errorMessage;
base.ValidationParameters.Add("expression", expression);
}
}
更新 2:
连接 jQuery.validator 的 Javascript:
(function ($) {
function attachMatchValidator(name, mustMatch) {
$.validator.addMethod(name, function (val, element, expression) {
var rg = new RegExp(expression, "gi");
return (rg.test(val) == mustMatch);
});
$.validator.unobtrusive.adapters.addSingleVal(name, "expression");
}
$("input[type=text]").each(function () {
$.each(this.attributes, function (i, attribute) {
if (attribute.name.length == 20 && attribute.name.substring(0, 14) == "data-val-match")
attachMatchValidator(attribute.name.substring(9, 20), true);
if (attribute.name.length == 23 && attribute.name.substring(0, 17) == "data-val-notmatch")
attachMatchValidator(attribute.name.substring(9, 23), false);
});
});
} (jQuery));