带有通用类型的DataAnnotations CustomValidator

时间:2011-07-11 20:29:27

标签: .net asp.net asp.net-mvc-3 data-annotations s#arp-architecture

这是一个使用S#arp架构的MVC 3项目。

我的域有几个继承NamedEntity的对象,这是一个扩展Entity并定义string Name属性的抽象类。

所有这些对象都分享了这样一个事实:它们必须是对象类型的唯一名称。

鉴于这些对象的集合相对较小(200将是极端情况),我不介意往返数据库以检查是否存在重复。

我的问题是,在保持DRY的同时轻松验证这一点的最佳方式是什么?

我经历了六次迭代,并不是特别喜欢它们中的任何一种。我尝试在ViewModel上创建[ValidUniqueName]属性,并且可以键入ViewModel EditViewModel<T> where T: NamedEntity。问题在于,由于Generic,该属性不知道要与之通信的正确的存储库/任务对象。

要解决此问题,我尝试在ViewModel中创建INamedEntityTasks<T>引用,并从ValidationContextValidUniqueName属性访问它。这不能按预期工作,因为属性不是通用的(它不可能),因此它不知道如何正确地将ValidationContext.ObjectInstance转换回可用的东西。

此时,我唯一能想到的就是创建单独的[ValidUniqueFoo] [ValidUniqueBar]等属性,这似乎很糟糕。或者,我可以在每个控制器中进行验证,但看起来同样糟糕。

2 个答案:

答案 0 :(得分:0)

您可以简单地将重载的构造函数添加到[ValidUniqueName]吗?或者我完全错过了这一点?

修改

您可以将两个类型参数传递给ViewModel类似

的内容
ViewModel<T, TRepository>

答案 1 :(得分:0)

目前看起来它似乎涉及肮脏的黑客或一些严重复杂的代码(见其他答案)。必须写

并不可怕
public class ValidUniqueCityAttribute : ValidationAttribute {

public override bool IsValid(object value)
    {
        if (value == null || !(value is CityCreateOrEditViewModel)) return base.IsValid(value);

        INamedEntityTasks<City> tasks = new NamedEntityTasks<City>();

        CityCreateOrEditViewModel vm = value as CityCreateOrEditViewModel;
        return !tasks.CheckForDuplicateName(vm.Entity.Id, vm.Entity.Name);
    }
}

对于每个NamedEntity,我们复制&amp;粘贴,搜索&amp;替换...是的,这是多余的,但它确实具有允许更大灵活性的优势,例如,如果我们想要以类别之外的其他方式验证城市名称(例如查找所有城市中的所有城市的主列表)例如,给定的状态,虽然这是完全做作和可怕的做法:))。