【飞秋】Asp.net MVC2 model验证 看似美好,实则让人失望。
最近幾天看了一下Asp.net MVC2的model驗證,初始的感覺讓我眼前一亮,于是去看了看它的源代碼,Validation和Metadata部分應該是從Dynamic Data哪里得到的靈感,一切似乎都那么美好,網上關于如何使用的文章頁很多,但是隨后的一段經歷讓我對Validation部分的代碼和設計產生了很大的不滿,它所夸贊的可以很容易與其它驗證框架的集成其實也并不是那么容易,下面我就來說說為什么我會對它不滿:
當前的MVC的驗證是在Model的屬性上加入Attribute,如下:
?
代碼
?1
?2???? [DisplayColumn("UserName", "Password", true)]
?3???? public class LogOnModel
?4???? {
?5???????? [Required]
?6???????? [DisplayName("User name")]
?7???????? public string UserName { get; set; }
?8
?9???????? [Required]
10???????? [DataType(DataType.Password)]
11???????? [DisplayName("Password")]
12???????? public string Password { get; set; }
13
14???????? [DisplayName("Remember me?")]
15???????? public bool RememberMe { get; set; }
16
17???????? public EmbeddedClass Embedded { get; set; }
18???? }
19
20???? public class EmbeddedClass
21???? {
22???????? [DisplayName("Try count")]
23???????? [Range(3, 5)]
24???????? public int TryCount { get; set; }
25
26???????? [DisplayName("Non Model")]
27???????? public string NonModel { get; set; }
28???? }
?
?
?
但是隨之而來的問題也來了,那就是
1。 過多的屬性(Attribute)使得Model過于臃腫,
2。一個Model代表的是一個類,它的實例應該有自己的Attribute, 如果是把Attribute加在了Model上,那么所有的實例只能使用同樣的Attribute,在我們的程序中很多的類經常是在很多函數中使用,并且每個函數會有不同的驗證要求,
3。 如果是簡單類型的參數,就不能做一些驗證了,譬如范圍驗證。
4。 如果類中的屬性是非值類型的(非值類型,不包括string),那么驗證并不會去驗證這個屬性實例內部的屬性,譬如我上面的Embedded 屬性。
這些讓我有了一個自己的想法,所以于是想把這些驗證放在配置文件中,于是仔細的看了MVC2綁定和驗證部分的源代碼,想看看如何擴展。我比較懶,DefaultModelBinder 這個類是asp.net mvc2 中用于綁定數據和調用驗證的最重要的類,其中Model的驗證部分是在 函數OnModelUpdated中被調用的,
?
?1???????? protected virtual void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) {
?2???????????? Dictionary<string, bool> startedValid = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
?3
?4???????????? foreach (ModelValidationResult validationResult in ModelValidator.GetModelValidator(bindingContext.ModelMetadata, controllerContext).Validate(null)) {
?5???????????????? string subPropertyName = CreateSubPropertyName(bindingContext.ModelName, validationResult.MemberName);
?6
?7???????????????? if (!startedValid.ContainsKey(subPropertyName)) {
?8???????????????????? startedValid[subPropertyName] = bindingContext.ModelState.IsValidField(subPropertyName);
?9???????????????? }
10
11???????????????? if (startedValid[subPropertyName]) {
12???????????????????? bindingContext.ModelState.AddModelError(subPropertyName, validationResult.Message);
13???????????????? }
14???????????? }
15???????? }
?
在這個函數中,ModelValidator.GetModelValidator(bindingContext.ModelMetadata, controllerContext),有這么一句,也就是獲得ModelValidator, 悲劇就在此函數中打開這個函數看看:
代碼
?1 public static ModelValidator GetModelValidator(ModelMetadata metadata, ControllerContext context) {
?2???????????? return new CompositeModelValidator(metadata, context);
?3???????? }
?4
?5???????? public abstract IEnumerable<ModelValidationResult> Validate(object container);
?6
?7???????? private class CompositeModelValidator : ModelValidator {
?8???????????? public CompositeModelValidator(ModelMetadata metadata, ControllerContext controllerContext)
?9???????????????? : base(metadata, controllerContext) {
10???????????? }
11
12???????????? public override IEnumerable<ModelValidationResult> Validate(object container) {
13???????????????? bool propertiesValid = true;
14
15???????????????? foreach (ModelMetadata propertyMetadata in Metadata.Properties) {
16???????????????????? foreach (ModelValidator propertyValidator in propertyMetadata.GetValidators(ControllerContext)) {
17???????????????????????? foreach (ModelValidationResult propertyResult in propertyValidator.Validate(Metadata.Model)) {
18???????????????????????????? propertiesValid = false;
19???????????????????????????? yield return new ModelValidationResult {
20???????????????????????????????? MemberName = DefaultModelBinder.CreateSubPropertyName(propertyMetadata.PropertyName, propertyResult.MemberName),
21???????????????????????????????? Message = propertyResult.Message
22???????????????????????????? };
23???????????????????????? }
24???????????????????? }
25???????????????? }
26
27???????????????? if (propertiesValid) {
28???????????????????? foreach (ModelValidator typeValidator in Metadata.GetValidators(ControllerContext)) {
29???????????????????????? foreach (ModelValidationResult typeResult in typeValidator.Validate(container)) {
30???????????????????????????? yield return typeResult;
31???????????????????????? }
32???????????????????? }
33???????????????? }
34???????????? }
35???????? }
?
它盡然是直接構造了一個CompositeModelValidator,這個CompositeModelValidator還是私有的,沒有用工廠模式,CompositeModelValidator不能繼承重寫,也就是說第一、如果想驗證,那就只能是驗證屬性,不能驗證簡單類型(當然有其他辦法可以解決這個問題),第二、也就是我上面提到的第四點,如果屬性是非值類型,對不起不能驗證其內部的屬性,第三、對于驗證一個Model那些部分我控制不了,只能是它的屬性。這三點使我我本來想擴展MVC2的驗證部分,也就是繼承自ModelValidator,看來是不行了,只能自己寫新的驗證部分了,只覺得MVC2有點失敗,比其MVC1的成功,它有點讓我失望。
?
?當然,這并不代表了,我上面所說的那些就做不了,我會在下一篇中給出利用Enterprise Library 的驗證來實現 擴展。
關注技術文章飛秋:http://www.freeeim.com/,24小時專業轉載。
總結
以上是生活随笔為你收集整理的【飞秋】Asp.net MVC2 model验证 看似美好,实则让人失望。的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenGL编程指南1:OpenGL简介
- 下一篇: Qt修炼手册6_图形:图形视图框架