閱讀470 返回首頁    go 阿裏雲 go 技術社區[雲棲]


[ASP.NET MVC]如何定製Numeric屬性/字段驗證消息

對於一個Numeric屬性/字段,ASP.NET MVC會自動進行數據類型的驗證(客戶端驗證),以確保輸入的是一個有效的數字,但是呈現在頁麵上的錯誤消息總是一段固定的文本:“The field {0} must be a number”,本篇提供一種解決方案使我們可以對此驗證消息進行定製。[源代碼從這裏下載]

目錄
一、針對Numeric屬性/字段默認驗證消息
二、默認的驗證消息來源於何處?
三、通過自定義ModelValidatorProvider替換NumericModelValidator
四、注冊自定義ModelValidatorProvider

我們先來通過一個簡單的例子來驗證這個問題,為此我們定義了如下一個表示員工信息的Employee類型,其中代表年齡的Age屬性類型為整型。

   1: public class Employee
   2: {
   3:     [Display(Name = "姓名")]
   4:     public string Name { get; set; }
   5:  
   6:     [Display(Name = "性別")]
   7:     public string Gender { get; set; }
   8:  
   9:     [Display(Name = "年齡")]
  10:     public int Age { get; set; }
  11: }

我們創建一個Model類型為Employee的View對某個元員工的信息進行修改。如下圖所示,當我們輸入一個非數字字符串作為Age字段的時候,驗證錯誤信息顯示為“The field 年齡 must be a number”,值得一提的是:當前線程的CurrentUICulture為zh-CN。

image

針對數字類型字段進行驗證的是一個名稱為NumericModelValidator的ModelValidator,不過這是個定義在System.Web.Mvc程序集中俄內部類型。如果采用Reflector查看其定義,可以發現用於返回錯誤消息的方法是一個名為MakeErrorString的靜態方法。如下麵的代碼所示,作為錯誤消息的字符串來源於內嵌於程序集中的資源文件。

   1: internal sealed class NumericModelValidator : ModelValidator
   2: {
   3:     //其他成員
   4:     private static string MakeErrorString(string displayName)
   5:     {
   6:         return string.Format(CultureInfo.CurrentCulture, MvcResources.ClientDataTypeModelValidatorProvider_FieldMustBeNumeric, new object[] { displayName });
   7:     }
   8: }

NumericModelValidator最終是通過ClientDataTypeModelValidatorProvider這個一個ModelValidatorProvider提供的。

如果我們想改變內部類型NumericModelValidator的錯誤消息,可以通過將ClientDataTypeModelValidatorProvider提供的NumericModelValidator替換成另一個ModelValidator。在這裏我們替換的是一個DataAnnotationsModelValidator,而它基於的ValidationAttribute是我們自定義的NumericAttribute。

如下麵的代碼片斷所示,內部類型NumericAttribute是ValidationAttribute的子類,並且實現了IClientValidatable接口。在這裏我麼隻考慮客戶端驗證,所以重寫的IsValid方法直接返回True,而GetClientValidationRules方法則返回一個包含一個驗證類型為“number”的ModelClientValidationRule對象的集合。我們使用FormatErrorMessage方法格式化後的字符串作為ModelClientValidationRule的ErrorMessage屬性。

   1: internal class NumericAttribute : ValidationAttribute, IClientValidatable
   2: {
   3:     public override bool IsValid(object value)
   4:     {
   5:         return true;
   6:     }
   7:     public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
   8:     {
   9:         yield return new ModelClientValidationRule { ValidationType = "number", ErrorMessage = this.FormatErrorMessage(metadata.DisplayName)};
  10:     }
  11: }

現在我們需要做的就是通過一個自定義ModelValidatorProvider將ClientDataTypeModelValidatorProvider提供的NumericModelValidator替換成基於NumericAttribute的DataAnnotationsModelValidator,所以我們定義了一個直接繼承自ClientDataTypeModelValidatorProvider的FilterableClientDataTypeModelValidatorProvider。如下麵的代碼所示,在重寫的GetValidators方法中我們完成了針對NumericModelValidator的替換。對於被創建的NumericAttribute來說,我們指定的錯誤消息也定義在Resource文件中(為了提供多語言的支持),而基於zh的內容為“{0}必須是一個數字!”。

   1: public class FilterableClientDataTypeModelValidatorProvider : ClientDataTypeModelValidatorProvider
   2: {
   3:     public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
   4:     {           
   5:         var allValidators = base.GetValidators(metadata, context);
   6:         var validators = new List<ModelValidator>();
   7:         foreach (var v in allValidators)
   8:         {
   9:             if (v.GetType().Name != "NumericModelValidator")
  10:             {
  11:                 validators.Add(v);
  12:             }
  13:             else
  14:             { 
  15:                 NumericAttribute attribute = new NumericAttribute{ ErrorMessage = Resources.FieldMustBeNumeric};
  16:                 DataAnnotationsModelValidator validator = new DataAnnotationsModelValidator(metadata, context, attribute);
  17:                 validators.Add(validator);
  18:             }
  19:         }
  20:         return validators;
  21:     }
  22: }

現在我們隻需要通過ModelValidatorProvider的注冊讓我們自定義的FilterableClientDataTypeModelValidatorProvider替換默認的ClientDataTypeModelValidatorProvider。在Global.asax中,針對FilterableClientDataTypeModelValidatorProvider的注冊可以通過如下的代碼來完成。

   1: public class MvcApplication : System.Web.HttpApplication
   2: {
   3:     //其他成員
   4:     protected void Application_Start()
   5:     { 
   6:          //其他操作
   7:         var clientDataTypeValidator = ModelValidatorProviders.Providers.OfType<ClientDataTypeModelValidatorProvider>().FirstOrDefault();
   8:         if (null != clientDataTypeValidator)
   9:         {
  10:             ModelValidatorProviders.Providers.Remove(clientDataTypeValidator);
  11:         }
  12:         ModelValidatorProviders.Providers.Add(new FilterableClientDataTypeModelValidatorProvider());
  13:     }
  14: }

現在運行我們的程序就可以得到我們定製的錯誤消息了。

image


作者:蔣金楠
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
原文鏈接

最後更新:2017-10-26 13:03:30

  上一篇:go  阿裏雲前端周刊 - 第 29 期
  下一篇:go  數據中心100G連接的發展驅動400G解決方案需求增長