惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

K
Kaspersky official blog
Martin Fowler
Martin Fowler
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
V
Visual Studio Blog
博客园_首页
Engineering at Meta
Engineering at Meta
The Cloudflare Blog
MongoDB | Blog
MongoDB | Blog
Blog — PlanetScale
Blog — PlanetScale
T
The Blog of Author Tim Ferriss
雷峰网
雷峰网
D
Docker
博客园 - 司徒正美
S
SegmentFault 最新的问题
M
MIT News - Artificial intelligence
博客园 - 叶小钗
博客园 - 三生石上(FineUI控件)
U
Unit 42
J
Java Code Geeks
A
About on SuperTechFans
N
Netflix TechBlog - Medium
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
Security Affairs
I
Intezer
Cisco Talos Blog
Cisco Talos Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
B
Blog RSS Feed
P
Privacy & Cybersecurity Law Blog
T
Tenable Blog
T
Threatpost
H
Hacker News: Front Page
G
Google Developers Blog
博客园 - 【当耐特】
Hugging Face - Blog
Hugging Face - Blog
Apple Machine Learning Research
Apple Machine Learning Research
L
Lohrmann on Cybersecurity
大猫的无限游戏
大猫的无限游戏
Google DeepMind News
Google DeepMind News
A
Arctic Wolf
S
Secure Thoughts
GbyAI
GbyAI
NISL@THU
NISL@THU
S
Security @ Cisco Blogs
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Webroot Blog
Webroot Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
O
OpenAI News
Spread Privacy
Spread Privacy
Application and Cybersecurity Blog
Application and Cybersecurity Blog

博客园 - 龚振

T4 模板编辑。 Login failed for user 'IIS APPPOOL\ASP.NET v4.0'. - 龚振 Keycode对照表 使用多字节字符集 syslink 不显示 Windows下JSP开发环境的配置 javascript 大括号,圆括号 清空数据库日志 数据库还原错误 (with move) 打开visual studio 智能感知(intellisense) for Unity Application Blocks (翻译) firefox ie DOM 级兼容性(一) ie ,firefox 兼容性,收集。。。。。 IE6.0、IE7.0 与 FireFox 收集,总是忘,还是收集了,以后总结下 web 版 ftp 数据库迁移可能遇到的问题 将物理内存制作为虚拟硬盘,提高系统速度 NET设计模式总结 自定义控件状态保存 关于Web服务器时间格式问题 关于Gridview templateField 无法 sort
MVC 表单验证的几种方式:
龚振 · 2012-04-21 · via 博客园 - 龚振

前提:数据建模是通过ADO.Net Entity 生成。原型如下:

 1    [EdmEntityTypeAttribute(NamespaceName="GoodsModel", Name="Customer")]
 2     [Serializable()]
 3     [DataContractAttribute(IsReference=true)]
 4     public partial class Customer : EntityObject
 5     {
 6         #region Factory Method
 7     
 8         /// <summary>
 9         /// Create a new Customer object.
10         /// </summary>
11         /// <param name="code">Initial value of the Code property.</param>
12         public static Customer CreateCustomer(global::System.Int32 code)
13         {
14             Customer customer = new Customer();
15             customer.Code = code;
16             return customer;
17         }
18 
19         #endregion
20         #region Primitive Properties
21     
22         /// <summary>
23         /// No Metadata Documentation available.
24         /// </summary>
25         [EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
26         [DataMemberAttribute()]    
27         public global::System.Int32 Code
28         {
29             get
30             {
31                 return _Code;
32             }
33             set
34             {
35                 if (_Code != value)
36                 {
37                     OnCodeChanging(value);
38                     ReportPropertyChanging("Code");
39                     _Code = StructuralObject.SetValidValue(value);
40                     ReportPropertyChanged("Code");
41                     OnCodeChanged();
42                 }
43             }
44         }
45         private global::System.Int32 _Code;
46         partial void OnCodeChanging(global::System.Int32 value);
47         partial void OnCodeChanged();
48     
49         /// <summary>
50         /// No Metadata Documentation available.
51         /// </summary>
52         [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
53         [DataMemberAttribute()]    
54         [ValidateLength(200)] 
55         public global::System.String Company
56         {
57             get
58             {
59                 return _Company;
60             }
61             set
62             {
63                 OnCompanyChanging(value);
64                 ReportPropertyChanging("Company");
65                 _Company = StructuralObject.SetValidValue(value, true);
66                 ReportPropertyChanged("Company");
67                 OnCompanyChanged();
68             }
69         }

  • 这种情况下最直接,也就是最容易想到的是,在控制器中直接调用ModelState.AddModelError().         

 1         [HttpPost]
 2         public ActionResult Create(Customer customer)
 3         {
 4             if (customer.Company.Length > ComanyMaxLength)
 5                 ModelState.AddModelError("Company""Company must be at most ComanyMaxLength characters long");
 6 
 7             if (ModelState.IsValid)
 8             {
 9                 return View(customer);
10             }
11             else
12             {
13                 new CustomerModels().CreateCustomer(customer);
14                 return RedirectToAction("Details""Customer"new { ID = customer.Code });
15             }
16         }

这样写简单,而且我们还有更简单的办法就是

  • 我们可以直接给MVC 中model filed 加上ValidateAttribute,下面是模板生成的ChangePasswordModel 中的代码。

1         [Required]
2         [ValidatePasswordLength]
3         [DataType(DataType.Password)]
4         [DisplayName("New password")]
5         public string NewPassword { getset; }

给所有需要的字段加上CustomerAttribute. 但问题来了,数据的里面有那么多的表,每个字段的长度也不一样,一一对应起来肯定麻烦,也容易出错。而且ADO.Net Entity 生成的Model 要加CustomerAttribute 也不是那么容易,同样工作量大,耦合性强。那有没有更好的方法呢,

  • 那就是利用ModelBinder 扩展,通过MetadatWorkspace 读取csdl的元数据进行验证。

 1     public class ValidationModelBinder : DefaultModelBinder
 2     {
 3         protected override void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, object value)
 4         {
 5             base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);
 6 
 7             if(value==nullreturn;
 8             var edmWorkspace = new MetadataWorkspace(new[] { "res://*/Entity.Goods.csdl" }, new Assembly[] { Assembly.GetAssembly(typeof(Customer)) });
 9             foreach (var edmType in edmWorkspace.GetItems<EdmType>(DataSpace.CSpace).Where(p => p.NamespaceName != "Edm" && p.Name == propertyDescriptor.ComponentType.Name))
10             {
11                 ReadOnlyMetadataCollection<Facet> facetList = (edmType as EntityType).Properties.First(p => p.Name == propertyDescriptor.Name).TypeUsage.Facets;
12                 facetList.Any(p =>
13                 {
14                     if (p.Name == "MaxLength")
15                     {
16                         if ((int)p.Value < value.ToString().Length)
17                             bindingContext.ModelState.AddModelError(propertyDescriptor.Name, "Company must be at most " + p.Value + " characters long");
18                         return true;
19                     }
20                     return false;
21                 });
22             }
23         }
24 
25     }

这样来耦合问题解决,大大减少了工作量。上面的代码需要优化,每个对象的属性绑定时都会调用,剩下的问题自己解决吧。将这个类注册下就可以了。

1         protected void Application_Start()
2         {
3             AreaRegistration.RegisterAllAreas();
4 
5             ModelBinders.Binders.Add(typeof(DataFacotry.Entity.Customer), new GoodsMvc.Component.ValidationModelBinder());
6 
7             RegisterRoutes(RouteTable.Routes);
8         }

同时也可以通过重载OnModelUpdated, 具体区别我也没有测试。

1         protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)

 这样看其来万事大吉了。 但我还是倾向于给ADO.Net Entity 生成的Model 添加CustomerAttribute. 到底能不能工作量少的情况下给所有的Filed 添加CustomerAttribute 呢?

  • 今天的重头戏来了,就是修改ADO.Net Entity 的生成GeneratorTemplate (T4 template)的实现。语法可以参考:http://msdn.microsoft.com/en-us/library/bb126478.aspx 在数据模型(.edmx file)的试图模式下,右键->Add code generation Item... 

可以搜索DataMemberAttribute在模板文件.tt中,定位到以下代码,添加高亮代码。

 1     /// <summary>
 2     /// <#=SummaryComment(primitiveProperty)#>
 3     /// </summary><#=LongDescriptionCommentElement(primitiveProperty, 1)#>
 4     [EdmScalarPropertyAttribute(EntityKeyProperty=<#=code.CreateLiteral(ef.IsKey(primitiveProperty))#>, IsNullable=<#=code.CreateLiteral(ef.IsNullable(primitiveProperty))#>)]
 5     [DataMemberAttribute()]    
 6 <#+ if(primitiveProperty.TypeUsage.Facets.Any(p=>p.Name=="MaxLength")){#>
 7     [ValidateLength(<#= primitiveProperty.TypeUsage.Facets["MaxLength"].Value #>)] 
 8 <#+
 9 }
10 #>

ValidataLength 继承于ValidationAttribute。