阿不

潜水

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  212 随笔 :: 0 文章 :: 3067 评论 :: 75 引用

公告

我们知道DataAnnotations是一个通用的数据模型元数据定义框架,其中最主要的部分是验证框架的定义。DataAnnotations可用户.NET平台的任何应用框架,但我们的项目中都是借助MVC来使用DataAnnotations。在MVC框架中,还对DataAnnotations进行了很多的扩展和适配:比如需要根据定义的DataAnnotations,生成客户端的验证;在Controller模型中绑定模型对数据进行有效性验证等等。我们的数据模型如果都是通过MVC入口,用户输入有的有效性验证的工作都可以交给MVC框架和DataAnnotations来完成。在我们的实践中,这样确实给我们带来了很大的的方便。

但是,当我们的数据入口不是走MVC通道,而是通过其它的入口(WebService,或其它服务)进来,这时我们就很难利用现有的MVC验证框架,我们可以模拟很多请求Context,并最终模拟ControllerContext,但是这样的工作实在太麻烦了。既然使用了DataAnnotations的验证标签定义,最好的方案还是复用这些标签,使用同一套验证机制。翻开DataAnnotations源码,希望能找到一个独立验证的辅助方法,很遗憾,并没有找到。

还是只能自己来实现这个功能,在没有下手之前好像还是有点麻烦的感觉(好像这是我们一贯的毛病,总是把很多事情都想的很难的样子,而且很多时候心里总会有点抵触,这点一定要在工作中好好改进)。不过,一切还是很简单的,主要还是要归功于TypeDescriptor。TypeDescriptor为我们准备好了类型相关的所有元信息,而且还可以通过它得到属性的PropertyDescriptor,这一下就简化了太多的工作。

public class ModelValidationError
{
    public string FieldName { get; set; }
    public string Message { get; set; }
}
public static class DataAnnotationHelper
{
    public static IEnumerable<ModelValidationError> IsValid<T>(this T o)
    {
        var descriptor = GetTypeDescriptor(typeof(T));

        foreach (PropertyDescriptor propertyDescriptor in descriptor.GetProperties())
        {
            foreach (var validationAttribute in propertyDescriptor.Attributes.OfType<ValidationAttribute>())
            {
                if (!validationAttribute.IsValid(propertyDescriptor.GetValue(o)))
                {
                    yield return new ModelValidationError() { FieldName = propertyDescriptor.Name, Message = validationAttribute.FormatErrorMessage(propertyDescriptor.Name) };
                }
            }
        }
    }
    private static ICustomTypeDescriptor GetTypeDescriptor(Type type)
    {
        return new AssociatedMetadataTypeTypeDescriptionProvider(type).GetTypeDescriptor(type);
    }
}

很简单,只需要几行代码就可以完成基于DataAnnotations的独立验证。值得注意的是,上面使用AssociatedMetadataTypeTypeDescriptionProvider来获取TypeDescriptor,是希望兼容MetadataType的方式注入元数据。有了上面的辅助方法,我们验证实体的有效性就变得非常轻松:

public class Model1
{
    [Required]
    public string Name { get; set; }

    [Range(1, 100)]
    public int Age { get; set; }
}
class Program
{
    static void Main(string[] args)
    {
        Model1 model = new Model1();
        foreach (var item in model.IsValid())
        {
            Console.WriteLine("FieldName:{0} Error Message:{1}", item.FieldName, item.Message);
        }
        Console.ReadLine();
    }
}

非常简单的扩展,非常完美的解决了我的问题。希望也对你有所帮助。

posted on 2010-11-07 20:05 阿不 阅读(...) 评论(...) 编辑 收藏