2011-04-11 109 views
1

由於無法驗證使用多個正則表達式模式(因爲驗證類型必須是唯一的)的屬性(使用不顯眼的客戶端驗證),因此我決定擴展FluentValidation,以便我可以執行以下操作。傳遞ErrorMessage進行客戶端驗證

RuleFor(x => x.Name).NotEmpty().WithMessage("Name is required") 
        .Length(3, 20).WithMessage("Name must contain between 3 and 20 characters") 
        .Match(@"^[A-Z]").WithMessage("Name has to start with an uppercase letter") 
        .Match(@"^[a-zA-Z0-9_\-\.]*$").WithMessage("Name can only contain: a-z 0-9 _ - .") 
        .Match(@"[a-z0-9]$").WithMessage("Name has to end with a lowercase letter or digit") 
        .NotMatch(@"[_\-\.]{2,}").WithMessage("Name cannot contain consecutive non-alphanumeric characters"); 



我需要弄清楚的最後一件事是如何傳遞其使用WithMessage()經由GetClientValidationRules()設置errormessage的,以便它在「數據-VAL-customregex [SOMEFANCYSTRINGHERETOMAKEITUNIQUE]」結束的屬性輸入元素。

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { 
    var rule = new ModelClientValidationRule(); 
    rule.ErrorMessage = [INSERT ERRORMESSAGE HERE]; 
    rule.ValidationType = "customregex" + StringFunctions.RandomLetters(6); 
    rule.ValidationParameters.Add("pattern", pattern); 

    yield return rule; 
} 


我一直在尋找的FluentValidation源代碼,但不能弄明白。任何人有任何想法?

回答

2

我一直在討論如何與傑里米·斯金納(創造者這樣做流利的驗證)在
http://fluentvalidation.codeplex.com/discussions/253505

他很友善地寫一個完整的例子。


更新
這是我們想出了代碼:

首先擴展,對於比賽和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 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 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 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:
Javascript來wireup jQuery.validator:

(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)); 
1

有點偏離主題,但也許有幫助。正則表達式非常強大,您是否考慮過將所有規則合併到一個正則表達式中?我認爲這就是爲什麼提供正則表達式驗證的屬性通常不允許每個屬性有多個實例。

因此,對於你的榜樣,你的正則表達式是:

"^[A-Z]([a-zA-Z0-9][_\-\.]{0,1}[a-zA-Z0-9]*)*[a-z0-9]$" 

和方便的地方進行測試:http://derekslager.com/blog/posts/2007/09/a-better-dotnet-regular-expression-tester.ashx

+0

事實上,我有這就是我曾在第一,但我想爲我的用戶提供一個詳細的錯誤信息,說明究竟是什麼錯誤,因此他們需要如何解決它。 – Fabian 2011-04-11 21:00:44

+0

對,有道理。這裏要做的另一件事就是自定義驗證。然後,您可以評估所有正則表達式並提供所需的任何錯誤消息。最重要的是,你不必走出基本的mvc框架:[CustomValidation(typeof(MyValidator),「MyCombinedRegexNameValidation」)] – Milimetric 2011-04-11 21:20:01

+0

這可以工作,但即時通訊尋找更好的解決方案,我可以很容易地使用多個屬性/模型,甚至後來甚至使用完全相同的JavaScript文件來附加驗證器clientside的項目。 – Fabian 2011-04-12 07:58:20