Asp.net表单自动验证(2)
在前一篇Asp.net表单自动验证中,我使用了Js作为中转来间接实现自动验证的功能。后台经过大家的评论发现,这个方法其实不安全,客户端可以通过禁用JS或者手动修改前台自动写入的验证规则来达到绕过验证的目的。不得不说,这个是致命的。如果这个问题不解决,设计的再简单也没人敢用。当我也在苦恼这个问题的时候billowdragon兄的评论给了我希望。一开始我以为他推荐ExpressionBuilder给我是为了解决我文章中提到的验证规则没有编辑器自动提示的遗憾的,后来一试也不对。也许是头脑中灵光一闪吧,想到了可以使用ExpressionBuilder代替JS的功能来实现Validate这个自定义属性的传输。还不知道ExpressionBuilder的同学,请先到http://www.cnblogs.com/firstyi/archive/2008/08/05/1260844.html这里去看一下。
其实看过前面一篇文章的同学都知道,所谓的自动验证的关键就是如果取得那个Validate自定义属性。既然通过JS保存在客户端的方法不妥,那么就通过ExpressionBuilder将他保存在服务器端缓存起来。如何实现?
首先自定义一个ValidateExpression继承于ExpressionBuilder,并实现里面的GetCodeExpression方法:
看过http://www.cnblogs.com/firstyi/archive/2008/08/05/1260844.html这篇文章的同学都知道是怎么回事了,我就不多解释了。我的思想就是既然ASP.net在解析文件的时候每次都会调用这个方法,那么我们可以利用这个机会取得Validate的值并缓存起来,如果下次再解析的时候就不重复保存了。看AddVlidateInfo这个方法:
这个方法很简单就是将解析的东西放入缓存中,如果已经有了这个键那么缓存不会添加重复项的。这里的key之所以要设计成这样是因为考虑到不同的页面当中可以出现名字相同的服务器控件,将页面与controlId绑定起来这样就不会出现重复的可能了。
然后再按钮点击事件中验证的时候就可以这样写:
检查某个控件是否需要验证的时候就去缓存中查找key如果存在则说明需要验证。这里我用了反射来获得Text属性(可能有些人要说这样性能不好了,但确实这样更加通用了,如果想设计一个东西性能高又简单方便确实有一定的难度)。
通过这种方法,该控件提供的功能不变(客户端验证,区域验证都不受影响),又能解决文章开始提到的安全性问题。看起来还不错。唯一担心的就是服务端缓存到底对性能有多少影响?如果随着页面表单的增加,缓存越来越多(一个项目达到几百个表单也有可能的吧?)影响到底有多大,能不能接受?我用luminji提到的http://www.cnblogs.com/luminji/archive/2011/09/02/2163525.html工具进行了一下测试,对比效果如下:
从上一幅图来看不考虑多出来的那100多个控件本身的HTML所占的字节,平均用户时间等待多了10ms左右。
而如果不使用自动验证控件,用户平均等待大概在31ms左右(上图),缩短了5ms。不知道我做的是个小测试算不算有效,如果是这样的话,影响也不是很大。如果你有更好的检测性能损失方便的方法的话,欢迎和我分享。
使用js实现不安全,使用ExpressionBuilder实现你又担心服务端缓存太多性能不好。好吧,不得不出杀招了。此方法简单有效,不需要前段辅助,不需要后台缓存,按需使用。这就是“ValidateGroup移花接木大法”。如果你不使用MS的validate控件,那么ValidateGroup基本对你无用(如果要使用本控件那就更用不到了)。既然放着都是放着,就借过来用用吧
这种方法,直接在后台就能取到判断规则了,简单有效。代码我就不写了,基本都一样。
写到这里我自己都觉得有点折腾了,为了几个验证折腾来折腾去的。如果各位同学觉得完全没有必要这样搞一笑而过便是,我也是某个时刻在写表单验证写烦了才生出这个儿念头的,尝试一下总归没有错的:),最后谢谢捧场!
https://files.cnblogs.com/qianlifeng/AutoValidate%E6%94%B9%E8%BF%9B.zip