2014-01-07 38 views
0

說我有一個自定義的驗證屬性ValidateFooIsCompatibleWith模型像這樣:如何爲模型上的複雜類型添加自定義ClientValidationRules(不顯眼的驗證)?

public class FooPart 
{ 
    public string Foo { get; set; } 

    public string Eey { get; set; } 
} 

public class FooableViewModel 
{ 
    public FooPart Foo1 { get; set; } 

    [ValidateFooIsCompatibleWith("Foo1")] 
    public FooPart Foo2 { get; set; } 
} 

比方說,我也有FooPart定義的自定義EditorTemplates:

@Html.TextBoxFor(m => m.Foo) 
@Html.TextBoxFor(m => m.Eey) 

這樣我的看法基本上是:

@Html.EditorFor(m => m.Foo1) 
@Html.EditorFor(m => m.Foo2) 

服務器端,驗證工作正常。但是,無論我嘗試什麼,我都無法獲取呈現的html來添加規則。

如果我執行IClientValidatable,事實證明GetClientValidationRules()永遠不會被調用。 (我之前成功使用了IClientValidatable以及「簡單」字段)。

我也嘗試通過繼承DataAnnotationsModelValidator<TAttribute>註冊我自己的自定義適配器,並在global.asax中註冊DataAnnotationsModelValidatorProvider.RegisterAdapter(...)該方法也無法調用GetClientValidationRules()

** **更新 如果同時添加自定義ModelMetadataProvider和一個自定義ModelValidatorProvider,這樣我可以設置斷點,我注意到行爲的一個有趣的一點:

  • 的請求到ModelMetadataProvider作出的元數據與ContainerTypeFooableViewModelModelTypeFooPart。然而,ModelValidatorProvider沒有相應的請求,所以我不能在那裏插入我的自定義客戶端驗證規則。
  • 請求到ModelValidatorProvider由具有的FooPart一個ContainerTypestring兩者的FooEey性質的ModelType。但在這個級別上,我不知道應用於屬性的屬性。

我該如何獲得MVC框架來爲複雜類型註冊自定義客戶端驗證規則?

回答

0
jQuery.validator.setDefaults({ 
    success: "valid" 
}); 
$("#foo").validate({ 
rules: 
{ 
    rule1: {required: true, min: 3}, 
    parent: 
    { 
     required: function(element) {return $("#age").val() < 13;}  
    } 
} 
}); 

複雜的類型似乎沒有理由麻煩,所以嘗試JQuery的驗證。取決於你想要驗證的內容,它可能會完成工作。

+0

不幸的是,在'FooPart'的EditorTemplate中,我需要應用基於屬性驗證的驗證 - 例如在問題的例子中,'FooPart'的編輯器模板有時需要添加客戶端驗證規則,例如'ValidateFooIsCompatibleWith'(使用jquery不顯眼的驗證),有時不會。所以jquery驗證器是解決方案的一部分,但我不認爲這解決了我的根本問題。 – Nathan

+0

我想我不明白你的問題,因爲你使用服務器發送驗證規則給客戶端,而不是通過JS或JQuery來處理客戶端驗證。你嘗試過'CustomValidationAttribute'嗎? – stink

0

我找到了一個解決方案:

首先,創建自定義模型元數據提供商(請參閱https://stackoverflow.com/a/20983571/24954),檢查的複雜類型的屬性,並存儲AdditionalValues集合,例如在客戶端可驗證規則廠在CreateMetadataProtoype覆蓋的CachedDataAnnotationsModelMetadataProvider

var ruleFactories = new List<Func<ModelMetadata, ControllerContext, IEnumerable<ModelClientValidationRules>>>(); 
... 
var clientValidatable = (IClientValidatable)attribute; 
ruleFactories.Add(clientValidatable.GetClientValidationRules); 
... 
result.AdditionalValues.Add("mycachekey", ruleFactories); 

接下來的,其註冊爲全局默認的元數據提供商。ASAX

protected void Application_Start() 
{ 
    ModelMetadataProviders.Current = new MyCustomModelMetadataProvider(); 
    .... 
} 

然後,我創建的HTML幫助,將處理modelmetata和創建/合併「數據VAL *」 HTML從每個AdditionalValues收集的屬性。

public static IDictionary<string, Object> MergeHtmlAttributes<TModel>(this HtmlHelper<TModel>, object htmlAttributes = null) 
{ 
    var attributesDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes); 
    //ensure data dictionary has unobtrusive validation enabled for the element 
    attributesDictionary.Add("data-val", "true"); 

    //loop through all the rule factories, and execute each factory to get all the rules 
    var rules = ruleFactory(helper.Html.ViewData.ModelMetadata, helper.Html.ViewContext); 

    //loop through and execute all rules in the ruleFactory collection in the AdditionalValues 
    //and add the data-val attributes for those. 
    attributesDictionary.add("data-val-" + rule.ValidationType, ruleErrorMessage); 

    //similarly for anything in the rule.ValidationParameters 
    attributesDictionary.Add("data-val-" + rule.ValidationType + "-" + parameterName, parameterValue); 

} 

最後,在我的編輯模板,調用HTML輔助(其中有FooPart1的`模型類型)每個複雜類型屬性,例如

@Html.TextBoxFor(m => m.Foo, Html.MergeHtmlAttributes(new { @class="Bar"})) 
@Html.TextBoxFor(m => m.Eey, Html.MergeHtmlAttributes()) 

其實我結束了創建,讓我自定義規則(主要用於錯誤消息)的複雜類型的各個字段的第二接口(具有相同簽名IClientValidatable)。我還擴展了幫助程序以接受可以使用我的自定義規則格式化的字符串參數。