Silverlight校验框架的限制——基于异常的验证机制
2009-11-13 16:48
267 查看
我们在项目中使用了Silverlight 3中新增的校验机制。一开始,感觉很不错:可以用标注的方式声明验证逻辑,自动设置校验控件,自动验证数据——一切似乎很好。但是很快我发现,Silverlight的校验机制也是存在严重限制的。
对于不熟悉Silverlight校验机制的朋友,我可以在这里作一个简单的介绍。关键在于System.ComponentModel.DataAnnotations这个程序集,它提供了一些标记属性,你可以为实体添加这些标记,然后在编写实体读写方法的时候添加一些触发校验逻辑的桩代码,那么内置有数据校验功能的控件(比如Label和DataForm等)就能自动识别、并按照你设定的值来进行校验。
下面是从Pro Silverlight 3 for C#中摘抄的一段代码。即使不看手册,其中规定的验证逻辑是很容易看懂的:
[StringLength(25)]
[Display(Name = "Model Name", Description = "This is the retail product name.")]
public string ModelName
{
get { return modelName; }
set
{
ValidationContext context = new ValidationContext(this, null, null);
context.MemberName = "ModelNumber";
Validator.ValidateProperty(value, context);
modelName = value;
OnPropertyChanged(new PropertyChangedEventArgs("ModelName"));
}
}
看起来很简单,而且我们使用的开头一段时间内运行得也相当不错,省去了很多手工校验的工作。直到有一天我们创建了某个新实体的时候,麻烦来了。
问题是这样的,项目需求要求我们保存某些客户信息,其中Email是必须填写的。实现此逻辑只要为属性加上一个Required标注即可。但问题在于,尽管Email是必须填写的,但我们却无法为它提供一个合理的默认值,所以开始的时候此属性是空字符串。另一方面,这个实体最初是从服务器端通过序列化得到的,而进行序列化和反序列化的时候也会调用Setter,从而调用校验逻辑,抛出异常——这是我们不希望的行为。虽然不希望,我们却不能去掉它,如果去掉的话,那么Silverlight的校验逻辑就不能工作了!
此问题的关键点在于,序列化的时候需要调用实体的Setter,界面绑定的时候也要调用Setter,但两种情况下需要的行为却是不同的。创建一个新实体的时候,其中某些属性有可能是无效的,但我们并不能因此阻止用户创建新对象,这时候是应当禁用验证逻辑的。 那么接下来的问题就是,实体的Setter中能不能识别到是在哪一种情况下调用的,从而打开或关闭验证呢?
开始我想到了Environment.StackTrace,根据调用堆栈来判断运行环境,应该可以识别出代码运行的场合。但是实验一下就发现:此路不通。StackTrace这个属性在Silverlight版本的CLR中是根本没有提供的,于是这个方向被堵死了。
有的组员提出,是否可以设置一个提示性的初始值,比如“<请填写>”?这个建议很快被否决了,因为要求用户来删掉无效的值再重新输入并不合理,也不友好。
然后又有人说,是否可以根据实体的Id来判断,如果是0则表示是新建的对象,不需要校验? 这也是不可行的,因为新建的对象在提交的时候同样需要校验。
当然还有一个办法是为界面绑定和数据传递分别生成两套实体,一套有数据校验,一套没有,然后写代码来在它们之间进行转换。但是想想也可以知道,这样工作量实在太大了,也增加了维护的难度。
最终我们采取了一个比较笨的办法:为实体添加一个IsUIBinding标志,一开始为false,在绑定到界面之前设置为true,提交服务器之前再复原为false。这样是可以解决问题了,不过程序员的负担就更重了——必须记住在合适的时候修改这个标记,否则程序就会出现bug。
这个结果让我对Silverlight验证框架感到有点遗憾。Silverlight的验证方法过于严格——一旦数据不合法,ValidationException就会抛出,于是所有后续代码都无法执行,如果运行环境没有做好处理此异常的准备的话,那么整个程序都会出错。而其他的场景——比如序列化的时候是没有办法处理此异常的,这大大限制了校验机制的应用场景。其实从设计上看,Silverlight使用了ValidationResult来收集校验失败信息,那么理论上讲,不使用异常,而根据ValidationResult收集的结果来判断也是完全可能的。但最终Silverlight还是采用了异常的方法。不过尽管有此遗憾,Silverlight的校验机制对于一般的数据验证还是不错的,目前我们也不太可能抛开它去完全实现一套自己的校验方法,只有在编程的时候多加注意了。
对于不熟悉Silverlight校验机制的朋友,我可以在这里作一个简单的介绍。关键在于System.ComponentModel.DataAnnotations这个程序集,它提供了一些标记属性,你可以为实体添加这些标记,然后在编写实体读写方法的时候添加一些触发校验逻辑的桩代码,那么内置有数据校验功能的控件(比如Label和DataForm等)就能自动识别、并按照你设定的值来进行校验。
下面是从Pro Silverlight 3 for C#中摘抄的一段代码。即使不看手册,其中规定的验证逻辑是很容易看懂的:
[StringLength(25)]
[Display(Name = "Model Name", Description = "This is the retail product name.")]
public string ModelName
{
get { return modelName; }
set
{
ValidationContext context = new ValidationContext(this, null, null);
context.MemberName = "ModelNumber";
Validator.ValidateProperty(value, context);
modelName = value;
OnPropertyChanged(new PropertyChangedEventArgs("ModelName"));
}
}
看起来很简单,而且我们使用的开头一段时间内运行得也相当不错,省去了很多手工校验的工作。直到有一天我们创建了某个新实体的时候,麻烦来了。
问题是这样的,项目需求要求我们保存某些客户信息,其中Email是必须填写的。实现此逻辑只要为属性加上一个Required标注即可。但问题在于,尽管Email是必须填写的,但我们却无法为它提供一个合理的默认值,所以开始的时候此属性是空字符串。另一方面,这个实体最初是从服务器端通过序列化得到的,而进行序列化和反序列化的时候也会调用Setter,从而调用校验逻辑,抛出异常——这是我们不希望的行为。虽然不希望,我们却不能去掉它,如果去掉的话,那么Silverlight的校验逻辑就不能工作了!
此问题的关键点在于,序列化的时候需要调用实体的Setter,界面绑定的时候也要调用Setter,但两种情况下需要的行为却是不同的。创建一个新实体的时候,其中某些属性有可能是无效的,但我们并不能因此阻止用户创建新对象,这时候是应当禁用验证逻辑的。 那么接下来的问题就是,实体的Setter中能不能识别到是在哪一种情况下调用的,从而打开或关闭验证呢?
开始我想到了Environment.StackTrace,根据调用堆栈来判断运行环境,应该可以识别出代码运行的场合。但是实验一下就发现:此路不通。StackTrace这个属性在Silverlight版本的CLR中是根本没有提供的,于是这个方向被堵死了。
有的组员提出,是否可以设置一个提示性的初始值,比如“<请填写>”?这个建议很快被否决了,因为要求用户来删掉无效的值再重新输入并不合理,也不友好。
然后又有人说,是否可以根据实体的Id来判断,如果是0则表示是新建的对象,不需要校验? 这也是不可行的,因为新建的对象在提交的时候同样需要校验。
当然还有一个办法是为界面绑定和数据传递分别生成两套实体,一套有数据校验,一套没有,然后写代码来在它们之间进行转换。但是想想也可以知道,这样工作量实在太大了,也增加了维护的难度。
最终我们采取了一个比较笨的办法:为实体添加一个IsUIBinding标志,一开始为false,在绑定到界面之前设置为true,提交服务器之前再复原为false。这样是可以解决问题了,不过程序员的负担就更重了——必须记住在合适的时候修改这个标记,否则程序就会出现bug。
这个结果让我对Silverlight验证框架感到有点遗憾。Silverlight的验证方法过于严格——一旦数据不合法,ValidationException就会抛出,于是所有后续代码都无法执行,如果运行环境没有做好处理此异常的准备的话,那么整个程序都会出错。而其他的场景——比如序列化的时候是没有办法处理此异常的,这大大限制了校验机制的应用场景。其实从设计上看,Silverlight使用了ValidationResult来收集校验失败信息,那么理论上讲,不使用异常,而根据ValidationResult收集的结果来判断也是完全可能的。但最终Silverlight还是采用了异常的方法。不过尽管有此遗憾,Silverlight的校验机制对于一般的数据验证还是不错的,目前我们也不太可能抛开它去完全实现一套自己的校验方法,只有在编程的时候多加注意了。
相关文章推荐
- 关于Struts2基于验证框架的输入校验的经验
- struts2基于验证框架的输入校验
- 一种少见的Dll注入方式(基于MS 应用程序验证机制)
- ERP框架开发中的License许可验证机制设计与实现 (包含源代码下载)
- jquery.validate.js校验框架中的验证用户名是否可用
- struts校验框架的一个异常
- 采用Best effort 1pc + 回滚补偿机制实现的一个distributed transaction (分布式事务框架).基于dubbo rpc服务上实现。
- 突破 Silverlight 自身限制, 做更好的动态加载导航机制(一)
- 基于ssh2架构的struts2验证框架错误解决
- 基于Keras框架的简易验证码识别网络的构建
- (转)基于Silverlight的快速开发框架RapidSL之开源
- 基于Theano的深度学习(Deep Learning)框架Keras学习随笔-09-约束限制
- 使用 nRoute 框架来实现基于 Silverlight 的桌面应用
- Struts2——框架校验(基于XML配置方式)
- Silverlight实例教程 - 自定义扩展Validation类,验证框架的总结和建议(转载)
- 初解,Scala语言中基于Actor的并发编程的机制,并展示了在Spark中基于Scala语言的Actor而产生的消息驱动框架Akka的使用,
- Asp.Net基于forms的验证机制
- 关于使用SSM整合的时候,使用hibernate校验框架出现500异常问题解决
- 一套基于asp.net的安全校验机制应用模型 !
- 看好你的门-验证机制被攻击(9)-不严谨的异常处理