ASP.NET MVC2 結合System.ComponentModel.DataAnnotations 提供了一套非常有效實體驗證架構。對於錯誤資訊的處理,它預設提供了兩種選擇:
- 字串常量
- 從程式集資源檔讀取
但是在我們這裡,我們有一套自己的資源檔方案,也就是我們需要自己控制項錯誤資訊的本地化操作。由於在中繼資料,我們只能提供常量,無法進行字串操作。一種比較直接和麻煩的辦法就是重寫所有的驗證規則,在驗證規則中對字串常量進行本地化操作。
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]public class CustomValidationAttribute : System.ComponentModel.DataAnnotations.ValidationAttribute{ public CustomValidationAttribute(string message) : base(() => message.Localize()) { }}
但是這樣做,一方面會比較麻煩,所有的驗證規則我們都要進行重寫;另一方面我們在設計model時就是特別的小心使用我們自己重寫過的規則才能達到我們的目的,這將大大降低開發體驗。為此,今天特別再次對照MVC2的源碼,希望能找到一個可用的擴充點來解決這個問題。最終發現我們可以通過重寫DataAnnotationsModelValidatorProvider的GetValidators方法來達到我們希望的效果:
public class CustomDataAnnotationsModelValidatorProvider : System.Web.Mvc.DataAnnotationsModelValidatorProvider{ protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes) { foreach (ValidationAttribute attribute in attributes.OfType<ValidationAttribute>()) { if (!string.IsNullOrWhiteSpace(attribute.ErrorMessage)) { attribute.ErrorMessage = attribute.ErrorMessage.Localize(); } } var validators = base.GetValidators(metadata, context, attributes); return validators; }}
代碼非常簡單,我們只是在調用GetValidators方法之前,對attribute的錯誤訊息進行一次本地化操作處理即可。通過這一次處理,我們可以同步處理用戶端驗證訊息和伺服器端驗證訊息的本地化。下面的工作就是用這個Provider來代替它的父類,在Global.asax添加下面的代碼即可完成:
ModelValidatorProviders.Providers.RemoveAt(0);ModelValidatorProviders.Providers.Insert(0, new CustomDataAnnotationsModelValidatorProvider());
通過這樣一個小小的擴充,就可以很完美的達到我們的目的。不過,為了這個小擴充,卻花費了我們不少的時間。