Asp.net MVC源碼分析–Model Validation(Client端)實現(1)

來源:互聯網
上載者:User

前兩篇我們介紹了ModelValidatoin Server 端的實現,那麼我們知道在Web.config 中如果我們把ClientValidationEnabled 設定為true時,那麼用戶端也可以支援表單驗證了. 那麼這部份功能是如果實現的呢?今天讓我們來一起學習Model validation client 端的實現.

一.ModelClientValidationRule類

這個類定義了如何輸出用戶端的一些資訊:

  • ErrorMessage:取得或設定使用者端驗證規則的錯誤訊息。
  • ValidationParameters:取得驗證參數清單。
  • ValidationType:取得或設定驗證類型。
 1   public class ModelClientValidationRule {
2
3 private readonly Dictionary<string, object> _validationParameters = new Dictionary<string, object>();
4 private string _validationType;
5
6 public string ErrorMessage {
7 get;
8 set;
9 }
10
11 public IDictionary<string, object> ValidationParameters {
12 get {
13 return _validationParameters;
14 }
15 }
16
17 public string ValidationType {
18 get {
19 return _validationType ?? String.Empty;
20 }
21 set {
22 _validationType = value;
23 }
24 }
25 }

我們知道了這個類的資料結構,那麼這些資料是如何輸出的呢?我們看一下RequiredAttributeAdapter類,在這裡定義了有一個GetClientValidationRules方法,這個方法返回了ModelClientValidationRequiredRule對象(包含了Required validation 需要輸出到用戶端的資料).

1  public class RequiredAttributeAdapter : DataAnnotationsModelValidator<RequiredAttribute> {
2 public RequiredAttributeAdapter(ModelMetadata metadata, ControllerContext context, RequiredAttribute attribute)
3 : base(metadata, context, attribute) {
4 }
5
6 public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() {
7 return new[] { new ModelClientValidationRequiredRule(ErrorMessage) };
8 }
9 }
二.如果讓得到自訂Client Validaton 資訊?

上面我們介紹了一些系統內建(Required)的Validation 的輸出,那麼我們如果需要自訂驗證規則如果來輸出用戶端資料呢?前面我們介紹了DataAnnotationsModelValidatorProvider.GetValidators 方法裡自訂的驗證是通過DefaultAttributeFactory委託來構造的,讓我們順著這個代碼來繼續我們的思路。

1   internal static DataAnnotationsModelValidationFactory DefaultAttributeFactory =
2 (metadata, context, attribute) => new DataAnnotationsModelValidator(metadata, context, attribute);

讓我接下來看一下DataAnnotationsModelValidator.GetClientValidationRules 方法的實現,我們看到下面代碼第4行,說明只有我們自訂的ValidationAtribute只有實現了IClientValidatable介面才能夠輸出用戶端資料。

 1   public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() {
2 IEnumerable<ModelClientValidationRule> results = base.GetClientValidationRules();
3
4 IClientValidatable clientValidatable = Attribute as IClientValidatable;
5 if (clientValidatable != null) {
6 results = results.Concat(clientValidatable.GetClientValidationRules(Metadata, ControllerContext));
7 }
8
9 return results;
10 }
三.如果輸出自訂Client Validaton 資訊到瀏覽器?

以上的分析是我們得到Cient validation 的資料,那麼我們怎麼輸出這些資料到瀏覽器呢? 

一般我們在View 頁面中的代碼都是這樣的:

1   <div class="editor-label">
2 Name
3 </div>
4 <div class="editor-field">
5 @Html.TextBoxFor(m => m.UserName)
6 @Html.ValidationMessageFor(m => m.UserName)
7 </div>

也就是說Client Validaton 資訊是通過Html.TextBoxFor方法來輸出的,那麼我們接下來研究一下這個方法是如何?的。

在InputExtension.cs 方件的InputHelper方法我們找到了一些與Client Validaton有關的程式碼片段,下面第9行代碼的GetUnobtrusiveValidationAttributes方法就實現了輸出。

1   // If there are any errors for a named field, we add the css attribute.
2 ModelState modelState;
3 if (htmlHelper.ViewData.ModelState.TryGetValue(fullName, out modelState)) {
4 if (modelState.Errors.Count > 0) {
5 tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
6 }
7 }
8
9 tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(name, metadata));

GetUnobtrusiveValidationAttributes方法的源碼:

 1  // Only render attributes if unobtrusive client-side validation is enabled, and then only if we've
2 // never rendered validation for a field with this name in this form. Also, if there's no form context,
3 // then we can't render the attributes (we'd have no <form> to attach them to).
4 public IDictionary<string, object> GetUnobtrusiveValidationAttributes(string name, ModelMetadata metadata) {
5 Dictionary<string, object> results = new Dictionary<string, object>();
6
7 // The ordering of these 3 checks (and the early exits) is for performance reasons.
8 if (!ViewContext.UnobtrusiveJavaScriptEnabled) {
9 return results;
10 }
11
12 FormContext formContext = ViewContext.GetFormContextForClientValidation();
13 if (formContext == null) {
14 return results;
15 }
16
17 string fullName = ViewData.TemplateInfo.GetFullHtmlFieldName(name);
18 if (formContext.RenderedField(fullName)) {
19 return results;
20 }
21
22 formContext.RenderedField(fullName, true);
23
24 IEnumerable<ModelClientValidationRule> clientRules = ClientValidationRuleFactory(name, metadata);
25 bool renderedRules = false;
26
27 foreach (ModelClientValidationRule rule in clientRules) {
28 renderedRules = true;
29 string ruleName = "data-val-" + rule.ValidationType;
30
31 ValidateUnobtrusiveValidationRule(rule, results, ruleName);
32
33 results.Add(ruleName, HttpUtility.HtmlEncode(rule.ErrorMessage ?? String.Empty));
34 ruleName += "-";
35
36 foreach (var kvp in rule.ValidationParameters) {
37 results.Add(ruleName + kvp.Key, kvp.Value ?? String.Empty);
38 }
39 }
40
41 if (renderedRules) {
42 results.Add("data-val", "true");
43 }
44
45 return results;
46 }

HtmlHelper 建構函式源碼:

 1   public HtmlHelper(ViewContext viewContext, IViewDataContainer viewDataContainer, RouteCollection routeCollection) {
2 if (viewContext == null) {
3 throw new ArgumentNullException("viewContext");
4 }
5 if (viewDataContainer == null) {
6 throw new ArgumentNullException("viewDataContainer");
7 }
8 if (routeCollection == null) {
9 throw new ArgumentNullException("routeCollection");
10 }
11
12 ViewContext = viewContext;
13 ViewDataContainer = viewDataContainer;
14 RouteCollection = routeCollection;
15 ClientValidationRuleFactory = (name, metadata) => ModelValidatorProviders.Providers.GetValidators(metadata ?? ModelMetadata.FromStringExpression(name, ViewData), ViewContext).SelectMany(v => v.GetClientValidationRules());
16 }

最終我們看到在GetUnobtrusiveValidationAttributes方法內部,MVC 調用了ClientValidationRuleFactory委託來得到clientRules對象它的類型是IEnumerable<ModelClientValidationRule>,這樣我們在Model上標記的Client Validation資料就輸出到了瀏覽器端。

--------------------------------------風搔分割線-------------------------------------------------

那麼通過以上這些分析我們知道了Server 端如何輸出Client Validation資料,那麼JavaScript是怎麼來進行驗證的呢? 

下一篇我們來分析jquery.validate.unobtrusive.js 的源碼,這裡面實現了MVC的用戶端驗證邏輯。

 

轉載請註明出處:http://www.cnblogs.com/RobbinHan/archive/2011/12/19/2293121.html

本文作者: 十一月的雨 http://www.cnblogs.com/RobbinHan

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.