详解ASP.NET MVC中属性标记的通用扩展方法

本文将讨论的是ASP.NET MVC中属性标记的通用扩展方法,在这里我们也将更进一步的了解ASP.NET MVC的作用。希望大家能用好ASP.MVC。

创新互联公司坚持“要么做到,要么别承诺”的工作理念,服务领域包括:网站设计、成都网站制作、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的乌什网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!

#T#

之前写过一篇文章《ASP.NET MVC中的验证》,唯一的遗憾就是在使用Data Annotation Validators方式验证的时候,如果数据库是Entityframework等自动生成的文件,就没有办法使用扩展属性标记进行标记。现在已经开始有了一些其它的ASP.NET MVC 验证框架,使用上跟Data Annotation Validators差不太多,但是普遍有这样的问题,如果数据库是Entityframework生成的edm文件,没有办法进行扩展属性标记。

今天在网上发现了另外一个 ASP.NET MVC 验证框架---xVal框架,使用上跟Data Annotation Validators非常接近,也有类似的问题。

简单介绍下,xVal是一个开源的ASP.NET MVC验证框架,有关它的介绍,可以参考:《xVal - a validation framework for ASP.NET MVC》

xVal使用了MS-PL的开源协议 ,也就是说,它允许用户看、修改和分发源代码,而不论出自商业用途还是非商业用途,类似BSD许可证。

 

xVal可以通过IRulesProvider接口,通过这个接口可以进行扩展,很明显,它只扩展了Castle框架跟NHibernate框架,通过如下两个程序集就可以看出来:

xVal.RulesProviders.CastleValidator.dllxVal.RulesProviders.NHibernateValidator.dll基本上可以得出结论:xVal没有提供对Entityframework框架的扩展,还需要我们做扩展。

最终,网上的一片文章给了我提示,问题得到了解决,解决的思路就是建立一个伙伴类,这个伙伴类跟原来的类的结构定义是一样的,在进行验证的时候,不对edm文件中的类进行验证,而是对伙伴类进行验证。

这里就以xVal框架为例进行Demo演示吧。

首先我们建立一个类模拟Entityframework生成的edm文件中的类,类的定义代码如下:

模拟EF中的User类

 
 
 
  1. public partial class User  
  2. {  
  3.     public string UserName { getset; }  
  4.     public string Password { getset; }  
  5.     public string Address { getset; }  
  6.     public string Telephone { getset; }  
  7.     public int Age { getset; }  
  8.     public string Email { get;set;}  

接下来我们建立一个伙伴类

伙伴类的代码

 
 
 
  1. public class UserMetadata  
  2.     {  
  3.         [Required]  
  4.         [StringLength(10)]  
  5.  
  6.         public string UserName { getset; }  
  7.  
  8.         [Required]  
  9.         [StringLength(18)]  
  10.         [DataType(DataType.Password)]  
  11.         public string Password { getset; }  
  12.  
  13.         [Required]  
  14.         [StringLength(100)]  
  15.         public string Address { getset; }  
  16.  
  17.         [Required]  
  18.         [DataType(DataType.PhoneNumber)]  
  19.         public string Telephone { getset; }  
  20.  
  21.         [Required]  
  22.         [Range(1, 100)]  
  23.         public int Age { getset; }  
  24.  
  25.         [Required]  
  26.         [DataType(DataType.EmailAddress)]  
  27.         public string Email { getset; }  
  28.     }  

再接下来,我们使用partial关键字为User类进行扩展,扩展类的定义如下:

扩展类的定义

 
 
 
  1. [MetadataType(typeof(UserMetadata))]  
  2. public partial class User  
  3. {     

注意这段代码:[MetadataType(typeof(UserMetadata))] 

为了方便大家阅读,我把整体代码贴出来,整体代码如下:

整体代码

 
 
 
  1. using System.ComponentModel.DataAnnotations;   
  2.  
  3. namespace MVCValidate.Models  
  4. {  
  5.     public partial class User  
  6.     {  
  7.         public string UserName { getset; }  
  8.         public string Password { getset; }  
  9.         public string Address { getset; }  
  10.         public string Telephone { getset; }  
  11.         public int Age { getset; }  
  12.         public string Email { get;set;}  
  13.     }  
  14.  
  15.     [MetadataType(typeof(UserMetadata))]  
  16.     public partial class User  
  17.     {   
  18.           
  19.     }  
  20.     public class UserMetadata  
  21.     {  
  22.         [Required]  
  23.         [StringLength(10)]  
  24.  
  25.         public string UserName { getset; }  
  26.  
  27.         [Required]  
  28.         [StringLength(18)]  
  29.         [DataType(DataType.Password)]  
  30.         public string Password { getset; }  
  31.  
  32.         [Required]  
  33.         [StringLength(100)]  
  34.         public string Address { getset; }  
  35.  
  36.         [Required]  
  37.         [DataType(DataType.PhoneNumber)]  
  38.         public string Telephone { getset; }  
  39.  
  40.         [Required]  
  41.         [Range(1, 100)]  
  42.         public int Age { getset; }  
  43.  
  44.         [Required]  
  45.         [DataType(DataType.EmailAddress)]  
  46.         public string Email { getset; }  
  47.     }  

接下来,我们要实现伙伴类跟原类的替换方法了,代码如下所示:

DataAnnotationsValidationRunner类的代码

 
 
 
  1. using System.Collections.Generic;  
  2. using System.ComponentModel;  
  3. using System.ComponentModel.DataAnnotations;  
  4. using System.Linq;  
  5. using xVal.ServerSide;  
  6.  
  7. namespace MVCValidate.Models  
  8. {  
  9.     internal static class DataAnnotationsValidationRunner  
  10.     {  
  11.         // TODO: DOES NOT SUPPORT METADATA TYPE  
  12.         ///// Warning: For some reason, DataTypeAttribute.IsValid() always returns "true", regardless of whether  
  13.         ///// it is actually valid. Need to improve this test runner to fix that.  
  14.         //public static IEnumerable GetErrors(object instance)  
  15.         //{  
  16.         //    return from prop in TypeDescriptor.GetProperties(instance).Cast()  
  17.         //           from attribute in prop.Attributes.OfType()  
  18.         //           where !attribute.IsValid(prop.GetValue(instance))  
  19.         //           select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), instance);  
  20.         //}  
  21.  
  22.         ///   
  23.         /// Get any errors associated with the model also investigating any rules dictated by attached Metadata buddy classes.  
  24.         ///   
  25.         ///   
  26.         ///   
  27.         public static IEnumerable GetErrors(object instance)  
  28.         {  
  29. var metadataAttrib = instance.GetType().GetCustomAttributes(typeof(MetadataTypeAttribute), true)
  30. .OfType().FirstOrDefault();  
  31.             var buddyClassOrModelClass = metadataAttrib != null ? metadataAttrib.MetadataClassType : instance.GetType();  
  32.             var buddyClassProperties = TypeDescriptor.GetProperties(buddyClassOrModelClass).Cast();  
  33.             var modelClassProperties = TypeDescriptor.GetProperties(instance.GetType()).Cast();  
  34.  
  35.             return from buddyProp in buddyClassProperties  
  36.                    join modelProp in modelClassProperties on buddyProp.Name equals modelProp.Name  
  37.                    from attribute in buddyProp.Attributes.OfType()  
  38.                    where !attribute.IsValid(modelProp.GetValue(instance))  
  39.                    select new ErrorInfo(buddyProp.Name, attribute.FormatErrorMessage(string.Empty), instance);  
  40.         }  
  41.     }  

完成以上的代码以后,大部分工作就完成了,接下来,我们在Controller中编写一个create方法,来模拟Create操作,代码如下所示:

Controller层的代码

 
 
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. using System.Web.Mvc;  
  6. using System.Web.Mvc.Ajax;  
  7.  
  8. using MVCValidate.Models;  
  9. using xVal.ServerSide;  
  10.  
  11. namespace MVCValidate.Controllers  
  12. {  
  13.     public class UserController : Controller  
  14.     {  
  15.         [AcceptVerbs(HttpVerbs.Post)]  
  16.         public ActionResult Create(User user)  
  17.         {  
  18.             var errors = DataAnnotationsValidationRunner.GetErrors(user);  
  19.             if (errors.Any())  
  20.             {  
  21.                 new RulesException(errors).AddModelStateErrors(ModelState,"user");  
  22.             }  
  23.  
  24.             return View();  
  25.         }  
  26.     }  

 接下来,编写View层的代码,比较简单,我就直接贴出来了,代码如下:

View层的代码

 
 
 
  1. <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %> 
  2.  xmlns="http://www.w3.org/1999/xhtml" > 
  3.  runat="server"> 
  4.     </strong>Create<strong> 
  5.  
  6.  
  7.     <%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %> 
  8.     <% using (Html.BeginForm()) {%> 
  9.  
  10.         
     
  11.             Fields 
  12.             

     

  13.                  for="UserName">UserName: 
  14.                 <%= Html.TextBox("user.UserName") %> 
  15.                 <%= Html.ValidationMessage("user.UserName")%> 
  16.             

     
  17.             

     

  18.                  for="Password">Password: 
  19.                 <%= Html.TextBox("user.Password") %> 
  20.                 <%= Html.ValidationMessage("user.Password")%> 
  21.             

     
  22.             

     

  23.                  for="Address">Address: 
  24.                 <%= Html.TextBox("user.Address")%> 
  25.                 <%= Html.ValidationMessage("user.Address")%> 
  26.             

     
  27.             

     

  28.                  for="Telephone">Telephone: 
  29.                 <%= Html.TextBox("user.Telephone")%> 
  30.                 <%= Html.ValidationMessage("user.Telephone")%> 
  31.             

     
  32.             

     

  33.                  for="Age">Age: 
  34.                 <%= Html.TextBox("user.Age")%> 
  35.                 <%= Html.ValidationMessage("user.Age")%> 
  36.             

     
  37.             

     

  38.                  for="Email">Email: 
  39.                 <%= Html.TextBox("user.Email")%> 
  40.                 <%= Html.ValidationMessage("user.Email")%> 
  41.             

     
  42.             

     

  43.                  type="submit" value="Create" /> 
  44.             

     
  45.          
  46.     <% } %> 
  47.     
     
  48.         <%=Html.ActionLink("Back to List", "Index") %> 
  49.     
 
  •  
  •  
  • 最终的效果如下图所示:

    ASP.NET MVC开源验证框架非常的多,只是有相似问题的更多,有了这个通用的方法,就可以很容易对其他验证框架进行扩展了。

    网站题目:详解ASP.NET MVC中属性标记的通用扩展方法
    网页路径:http://www.csdahua.cn/qtweb/news47/224347.html

    网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

    广告

    声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网