[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。
針對數字類型字段進行驗證的是一個名稱為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: }
現在運行我們的程序就可以得到我們定製的錯誤消息了。
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
最後更新:2017-10-26 13:03:30