下面进行测试:
可以看到验证的错误信息都按预期返回了。
再试试另外一组测试:
下面考虑下如果据注解无法满足验证要求的情况,这时就需要写自定义的验证。
之前文章讲过,有几种方法可以写自定义验证逻辑:
自定义验证属性标签(数据注解),编写一个继承于ValidationAttribute的类
让Resource类实现IValidatableObject接口
使用FluentValidation以及类似的第三方库
直接在方法里写验证逻辑
我比较倾向于后两种方法,尤其是第三种。但是由于本文主要是讲RESTful API相关的,所以我先避免过多的使用第三方库,我暂时先采用第四种方法。
假设我要求City的name属性值不可以是“中国”:
这里要用到ModelState的AddModelError方法。
测试:
OK.
下面看一下PUT的验证。
大部分情况下,PUT的验证可能和POST是一样的,但是有时还是不一样的,所以分别写两个ResourceModel对应POST和PUT的优势就体现出来了。
但是这两个类的大部分代码还是一样的,所以可以采取使用抽象父类的方法来去掉重复的代码,建立CityResource:
注意属性一定要使用virtual关键字,因为在子类里我们可能会重写属性。
在这里我把Description的Required约束去掉了。
再看CityAddResource:
继承抽象类即可,属性和验证完全一样。
再看CityUpdateResource:
这里,我对Description属性添加了Required约束,而其它约束和父类保持一致。
最后修改PUT的Action方法:
测试,POST:
OK。
再测试PUT,尤其是Description属性:
子类里Description的约束进行了检查。
再测试父类里Description的约束:
OK, 说明子类里Description的约束和父类里Description的约束都起作用。
在子类CityUpdateResource里,还可以这样写:
这样或许更清晰。
到目前为止,我使用的是数据注解的方式来为ResourceModel添加验证规则,这样做其实不是很好,没有关注点分离(Soc,Seperation of Concerns)。
而且,我们的自定义验证代码也是到处重复的写,这样也不对。