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

推荐订阅源

Stack Overflow Blog
Stack Overflow Blog
量子位
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
美团技术团队
小众软件
小众软件
aimingoo的专栏
aimingoo的专栏
Recent Announcements
Recent Announcements
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Microsoft Security Blog
Microsoft Security Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
酷 壳 – CoolShell
酷 壳 – CoolShell
J
Java Code Geeks
V
V2EX
大猫的无限游戏
大猫的无限游戏
D
DataBreaches.Net
博客园 - Franky
爱范儿
爱范儿
T
Tailwind CSS Blog
A
About on SuperTechFans
Google DeepMind News
Google DeepMind News
博客园_首页
B
Blog RSS Feed
博客园 - 司徒正美
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知

博客园 - 阿不

10年总结,得到与失去 Windows phone7 软件发布:理财计算器(包括wp7房贷计算器,wp7个税计算器,wp7存款利息计算器) 从.NET到Mono-记Kooboo CMS对Mono的兼容历程:三、平台的兼容性 从.NET到Mono-记Kooboo CMS对Mono的兼容历程:二、大小写敏感问题,到处都是地雷 从.NET到Mono-记Kooboo CMS对Mono的兼容历程:一、Mono以及移平台的基本注意要点 ASP.NET MVC3 on Mono的折腾(一):Windows下的部署 ASP.NET MVC3 on Mono的折腾(二):Linux(openSUSE)下的部署 迟到的2010总结 周末随想之移动随笔 NVelocity for ASP.NET MVC ASP.NET 4.0在IIS6原生支持没有后缀名的URL请求 闲语MVC3和Razor ASP.NET MVC3 RC2和一些小bug ASP.NET MVC 的统一异常处理有多难?(衍生的意图,出错后如何保持表单的状态?) Attribute与TypeDescriptor的故事 DataContext是否可以静态化? 今日手记:ASP.NET进程内的定时任务 有趣的同名不同约束泛型扩展方法的编译问题 在程序中动态执行T4模板,如何传参数给T4模板?
DataAnnotation脱离MVC独立验证
阿不 · 2010-11-07 · via 博客园 - 阿不

我们知道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();
    }
}

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