本篇主要講解ModelValidatorProvider 和ModelValidator兩種類型的自定義實現,前者是Model驗證提供程序,而ModelValidator類型則是Model驗證執行類型,在下面的示例中會使用Model驗證提供程序結合Model驗證執行類型來執行Model驗證,就是使用上個篇幅中所講的實現個Model綁定器繼承自DefaultModelBinder類型,在自定義Model綁定器中使用ModelValidator類型。框架
ModelValidatoride
深呼吸一下,直接進入主題。函數
在咱們定義自定義的ModelValidator類型以前,先看一下ModelValidator類型的定義,代碼1-1.ui
代碼1-1spa
public abstract class ModelValidator { protected ModelValidator(ModelMetadata metadata, ControllerContext controllerContext); protected internal ControllerContext ControllerContext { get; } public virtual bool IsRequired { get; } // // 摘要: // 獲取模型驗證程序的元數據。 // // 返回結果: // 模型驗證程序的元數據。 protected internal ModelMetadata Metadata { get; } public virtual IEnumerable<ModelClientValidationRule> GetClientValidationRules(); public static ModelValidator GetModelValidator(ModelMetadata metadata, ControllerContext context); // // 摘要: // 在派生類中實現時驗證對象。 // // 參數: // container: // 容器。 // // 返回結果: // 驗證結果的列表。 public abstract IEnumerable<ModelValidationResult> Validate(object container); }
代碼1-1中,咱們能夠看到ModelValidator類型的構造是能夠重寫的,這樣便於咱們自定義一些所需的數據,不過下面的示例中並無這麼作,目的是在於簡單的演示,而後咱們再看一下Metadata屬性,這個屬性很是重要了,它表示封裝着所要進行驗證的Model或者是Model屬性的信息在此提醒你們關注一下,最後要看的就是Validate()抽象方法了,咱們自定義類型必須實現的這麼一個方法,在它的返回類型中有個ModelValidationResult類型,咱們就來看一下ModelValidationResult類型,代碼1-2.code
代碼1-2orm
public class ModelValidationResult { public ModelValidationResult(); // 摘要: // 獲取或設置成員名。 // // 返回結果: // 成員名。 public string MemberName { get; set; } // // 摘要: // 獲取或設置驗證結果消息。 // // 返回結果: // 驗證結果消息。 public string Message { get; set; } }
正如你們所看到的,代碼1-2沒啥好說的,看完本篇天然明白。對象
ASP.NET MVC Model驗證(三)和ASP.NET MVC Model驗證(一)中的示例想必有的朋友是看過了,沒看過的朋友建議去快速的看一下篇幅一和篇幅三的示例部分(本篇示例的基礎依賴上篇的基礎部分,篇幅長度緣由這裏就再也不次說明了),在這裏我想說的是Model驗證也是分級別的,就是上篇中也有提到過的Model級驗證和Model屬性級驗證,在下面的示例中,我把上篇篇幅中的驗證過程拆成三個部分(能夠寫在一塊兒,便於理解)。blog
我把第一個部分定義爲Model屬性級驗證,咱們來看一下示例代碼1-3。繼承
代碼1-3
public class MyCustomModelPropertyValidator : ModelValidator { public MyCustomModelPropertyValidator(ModelMetadata modelMetadata, ControllerContext controllContext) : base(modelMetadata, controllContext) { } public override IEnumerable<ModelValidationResult> Validate(object container) { switch (Metadata.PropertyName) { case "ID": if (string.IsNullOrEmpty((string)container) || (string)container == "") { return new ModelValidationResult[] { new ModelValidationResult() { MemberName="ID", Message= "請輸入ID,ID不能爲空!" } }; } break; case "UserID": if (string.IsNullOrEmpty((string)container) || (string)container == "") { return new ModelValidationResult[] { new ModelValidationResult() { MemberName="UserID", Message= "請輸入用戶帳戶,用戶帳戶不能爲空!" } }; } break; case "Password1": if (string.IsNullOrEmpty((string)container) || (string)container == "") { ControllerContext.Controller.TempData.Add("Password1", false); return new ModelValidationResult[] { new ModelValidationResult() { MemberName="Password1", Message= "請輸入登陸密碼,登陸密碼不能爲空!" } }; } break; case "Password2": if (string.IsNullOrEmpty((string)container) || (string)container == "") { ControllerContext.Controller.TempData.Add("Password2", false); return new ModelValidationResult[] { new ModelValidationResult() { MemberName="Pssword2", Message= "請再次輸入密碼,密碼不能爲空!" } }; } break; case "Name": return Enumerable.Empty<ModelValidationResult>(); } return Enumerable.Empty<ModelValidationResult>(); } }
首先咱們在代碼1-3中定義了個MyCustomModelPropertyValidator類型,而且定義了構造函數這點很是重要(看到Model驗證提供程序部分就明白了),在Validate()方法中對一些屬性進行了基本的的驗證,而且依據方法所約束的返回類型去返回,對於代碼的實現部分,看過上篇的朋友就知道了在默認的Model綁定器執行Model屬性綁定的時候會進行Model屬性驗證,會在遍歷中循環的調用這個MyCustomModelPropertyValidator類型的驗證方法,這裏有不明白的朋友能夠去看一下上篇。
咱們再來看第二部分,第二部分的主要驗證是驗證兩次輸入的密碼是不是相同的,來看示例代碼1-4。
代碼1-4
public class MyCustomModelPassWordValidator : ModelValidator { public MyCustomModelPassWordValidator(ModelMetadata modelMetadata, ControllerContext controllerContext) : base(modelMetadata, controllerContext) { } public override IEnumerable<ModelValidationResult> Validate(object container) { Models.RegistrationInformation regInfo = Metadata.Model as Models.RegistrationInformation; if (regInfo != null) { if (!ControllerContext.Controller.TempData.ContainsKey("Password1") && !ControllerContext.Controller.TempData.ContainsKey("Password2")) { if (regInfo.Password1 != regInfo.Password2) { return new ModelValidationResult[] { new ModelValidationResult() { MemberName="Password2", Message="請從新輸入密碼,與上次輸入密碼不一樣!" } }; } } } return Enumerable.Empty<ModelValidationResult>(); } }
在代碼1-4中,有細心的朋友發現了跟代碼1-3的實現方式有很大的區別,對的由於我把這個MyCustomModelPassWordValidator類型定義爲Model級驗證了,MyCustomModelPassWordValidator類型所被調用的位置是在默認Model綁定器對Model屬性驗證完畢而且進行綁定了事後,再在默認Model綁定器的OnModelUpdated()方法中調用的,因此上述能夠直接經過Metadata的Model屬性直接獲取Model的值,由此來進行驗證,而這句ControllerContext.Controller.TempData.ContainsKey("Password1")代碼的含義是判斷在Model的Password1屬性在屬性級驗證的時候是否經過了,由於每一個Model驗證器之間沒法傳遞消息,只有ControllerContext是指向一個引用的,全部用它來作數據信息的承載。在代碼1-3中已經定義了。(對於第二部分的理解不太明白的朋友能夠結合上篇和本篇來看)
如今咱們再看第三部分,意思和第二部分同樣,示例代碼1-5。
代碼1-5
public class MyCustomModelNameValidator : ModelValidator { public MyCustomModelNameValidator(ModelMetadata modelMetadata, ControllerContext controllerConttext) : base(modelMetadata, controllerConttext) { } public override IEnumerable<ModelValidationResult> Validate(object container) { Models.RegistrationInformation regInfo = Metadata.Model as Models.RegistrationInformation; if (regInfo != null) { if (string.Compare(regInfo.Name, "jinyuan", true) == 0) { return new ModelValidationResult[] { new ModelValidationResult() { MemberName="", Message="您輸入的名稱違法了,當即更改否則查水錶" } }; } } return Enumerable.Empty<ModelValidationResult>(); } }
代碼1-5的功能就是在Model級驗證時對Model的Name屬性進行驗證。
ModelValidatorProvider
上個小節定義了三個部分,第一部分爲Model屬性級驗證,二三部分皆爲Model級驗證,然而在默認的Model綁定器(DefaultModelBinder類型)執行的時候,它才無論呢,它只負責從ModelValidatorProviders.Providers中獲取咱們自定義的Model驗證器提供程序(ModelValidatorProvider類型實例),再由Model驗證器提供程序給它提供Model驗證器,這個時候就須要咱們的自定義的Model驗證器提供程序具備判斷咱們自身是在哪裏被調用的,而且返回對應的Model驗證器,來看示例代碼1-6。
代碼1-6
namespace MvcApplication.ModelValidators { public class MyCustomModelValidatorProvider:ModelValidatorProvider { public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context) { if (metadata.ContainerType == typeof(Models.RegistrationInformation)) { return new ModelValidator[] { new MyCustomModelPropertyValidator(metadata,context) }; } else if (metadata.ModelType == typeof(Models.RegistrationInformation)) { return new ModelValidator[] { new MyCustomModelPassWordValidator(metadata,context), new MyCustomModelNameValidator(metadata,context) }; } return Enumerable.Empty<ModelValidator>(); } } }
在代碼1-6中,咱們定義了個自定義的Model驗證器提供程序MyCustomModelValidatorProvider類型,在MyCustomModelValidatorProvider類型中是根據GetValidators()方法的參數metadata所包含的信息來判斷本身被默認的Model綁定器(DefaultModelBinder類型)調用的位置。(對於Model元數據部分你們可查看我前面跟你們分享的Model元數據系列)
到了這裏幾乎就已經所有完成了,如今註冊到系統中是不能使用的,有的朋友會罵了,不能用瞎扯蛋扯半天,你們莫急,聽我解釋,是由於咱們自定義的Model驗證器和Model驗證器提供程序都要受到MVC框架的默認的Model綁定器(DefaultModelBinder類型)調用的約束,是必須按照它方法內部定義的來往下寫,在這裏咱們不圖省事,再定義一個自定義實現DefaultModelBinder類型的Model綁定器,來看示例代碼1-7。
代碼1-7
public class MyCustomModelValidatorDefaultModelBinder : DefaultModelBinder { protected override void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value) { base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value); foreach (ModelValidator modelValidator in ModelValidatorProviders.Providers.GetValidators(bindingContext.PropertyMetadata[propertyDescriptor.Name], controllerContext)) { IEnumerable<ModelValidationResult> modelValidationResults = modelValidator.Validate(value); foreach (ModelValidationResult modelValidationResult in modelValidationResults) { bindingContext.ModelState.AddModelError(modelValidationResult.MemberName, modelValidationResult.Message); } } } protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) { //base.OnModelUpdated(controllerContext, bindingContext); foreach (ModelValidator modelValidator in ModelValidatorProviders.Providers.GetValidators(bindingContext.ModelMetadata, controllerContext)) { IEnumerable<ModelValidationResult> modelValidationResults = modelValidator.Validate(null); foreach (ModelValidationResult modelValidationResult in modelValidationResults) { bindingContext.ModelState.AddModelError(modelValidationResult.MemberName, modelValidationResult.Message); } } } }
有了代碼1-7中的Model綁定器就能夠吻合咱們前面所定義的Model驗證器以及提供程序了。
我要把MyCustomModelValidatorProvider類型和MyCustomModelValidatorDefaultModelBinder類型註冊到系統中,將示例代碼1-8部分添加至Global.asax文件的Application_Start()方法中。
代碼1-8
ModelBinders.Binders.Add(typeof(Models.RegistrationInformation), new Binders.MyCustomModelValidatorDefaultModelBinder()); ModelValidatorProviders.Providers.Insert(0, new ModelValidators.MyCustomModelValidatorProvider());
看下圖1,圖1爲初始的展現頁面,圖2爲圖1中點擊提交後執行驗證事後。
圖1
圖2
做者:金源
出處:http://www.cnblogs.com/jin-yuan/
本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面