replica watches | rolex replica | replica rolex | replica watches | christian louboutin shoes | replica watches | fake watches | replica watches

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

来源: 未知   日期:2009-12-04  我要评论  胶粘剂 结构胶 硅胶 密封胶 中国胶粘剂网
xVal可以通过IRulesProvider接口,通过这个接口可以进行扩展,很明显,它只扩展了Castle框架跟NHibernate框架,通过如下两个程序集就可以看出来: xVal.RulesProviders.CastleValidator.dllxVal.RulesProviders.NHi

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<ErrorInfo> GetErrors(object instance)  
  15.         //{  
  16.         //    return from prop in TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>()  
  17.         //           from attribute in prop.Attributes.OfType<ValidationAttribute>()  
  18.         //           where !attribute.IsValid(prop.GetValue(instance))  
  19.         //           select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), instance);  
  20.         //}  
  21.  
  22.         /// <summary>  
  23.         /// Get any errors associated with the model also investigating any rules dictated by attached Metadata buddy classes.  
  24.         /// </summary>  
  25.         /// <param name="instance"></param>  
  26.         /// <returns></returns>  
  27.         public static IEnumerable<ErrorInfo> GetErrors(object instance)  
  28.         {  
  29. var metadataAttrib = instance.GetType().GetCustomAttributes(typeof(MetadataTypeAttribute), true)
  30. .OfType<MetadataTypeAttribute>().FirstOrDefault();  
  31.             var buddyClassOrModelClass = metadataAttrib != null ? metadataAttrib.MetadataClassType : instance.GetType();  
  32.             var buddyClassProperties = TypeDescriptor.GetProperties(buddyClassOrModelClass).Cast<PropertyDescriptor>();  
  33.             var modelClassProperties = TypeDescriptor.GetProperties(instance.GetType()).Cast<PropertyDescriptor>();  
  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<ValidationAttribute>()  
  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<MVCValidate.Models.User>" %> 
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
  3. <html xmlns="http://www.w3.org/1999/xhtml" > 
  4. <head runat="server"> 
  5.     <title>Create</title> 
  6. </head> 
  7. <body> 
  8.     <%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %> 
  9.     <% using (Html.BeginForm()) {%> 
  10.  
  11.         <fieldset> 
  12.             <legend>Fields</legend> 
  13.             <p> 
  14.                 <label for="UserName">UserName:</label> 
  15.                 <%= Html.TextBox("user.UserName") %> 
  16.                 <%= Html.ValidationMessage("user.UserName")%> 
  17.             </p> 
  18.             <p> 
  19.                 <label for="Password">Password:</label> 
  20.                 <%= Html.TextBox("user.Password") %> 
  21.                 <%= Html.ValidationMessage("user.Password")%> 
  22.             </p> 
  23.             <p> 
  24.                 <label for="Address">Address:</label> 
  25.                 <%= Html.TextBox("user.Address")%> 
  26.                 <%= Html.ValidationMessage("user.Address")%> 
  27.             </p> 
  28.             <p> 
  29.                 <label for="Telephone">Telephone:</label> 
  30.                 <%= Html.TextBox("user.Telephone")%> 
  31.                 <%= Html.ValidationMessage("user.Telephone")%> 
  32.             </p> 
  33.             <p> 
  34.                 <label for="Age">Age:</label> 
  35.                 <%= Html.TextBox("user.Age")%> 
  36.                 <%= Html.ValidationMessage("user.Age")%> 
  37.             </p> 
  38.             <p> 
  39.                 <label for="Email">Email:</label> 
  40.                 <%= Html.TextBox("user.Email")%> 
  41.                 <%= Html.ValidationMessage("user.Email")%> 
  42.             </p> 
  43.             <p> 
  44.                 <input type="submit" value="Create" /> 
  45.             </p> 
  46.         </fieldset> 
  47.     <% } %> 
  48.     <div> 
  49.         <%=Html.ActionLink("Back to List", "Index") %> 
  50.     </div> 
  51. </body> 
  52. </html> 

最终的效果如下图所示:

效果图

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

顶一下
(0)
0%
踩一下
(0)
0%
最新评论 查看所有评论
发表评论 查看所有评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 密码: 验证码: