asp.net-mvc - domain event




将验证属性从域实体映射到DTO (5)

我有一个标准的Domain Layer实体:

public class Product
{
    public int Id { get; set; }

    public string Name { get; set; }

    public decimal Price { get; set;}
}

它具有某种验证属性:

public class Product
{
    public int Id { get; set; }

    [NotEmpty, NotShorterThan10Characters, NotLongerThan100Characters]
    public string Name { get; set; }

    [NotLessThan0]
    public decimal Price { get; set;}
}

如您所见,我完全弥补了这些属性。 这里使用的验证框架(NHibernate Validator,DataAnnotations,ValidationApplicationBlock,Castle Validator等)并不重要。

在我的客户端层,我也有一个标准设置,我不使用域实体本身,而是将它们映射到我的视图层使用的ViewModels(又名DTO):

public class ProductViewModel
{
    public int Id { get; set; }

    public string Name { get; set; }

    public decimal Price { get; set;}
}

然后我们说我希望我的客户端/视图能够执行一些基本的属性级验证。

我看到我能做到这一点的唯一方法是重复ViewModel对象中的验证定义:

public class ProductViewModel
{
    public int Id { get; set; }

    // validation attributes copied from Domain entity
    [NotEmpty, NotShorterThan10Characters, NotLongerThan100Characters]
    public string Name { get; set; }

    // validation attributes copied from Domain entity
    [NotLessThan0]
    public decimal Price { get; set;}
}

这显然不能令人满意,因为我现在在ViewModel(DTO)层中重复了业务逻辑(属性级验证)。

那可以做些什么呢?

假设我使用像AutoMapper这样的自动化工具将我的Domain实体映射到我的ViewModel DTO,那么以某种方式将映射属性的验证逻辑转移到ViewModel也不是很酷吗?

问题是:

1)这是个好主意吗?

2)如果是这样,可以吗? 如果没有,有什么替代方案,如果有的话?

提前感谢您的任何输入!


为什么不使用界面来表达你的意图? 例如:

public interface IProductValidationAttributes {
    [NotEmpty, NotShorterThan10Characters, NotLongerThan100Characters]
    string Name { get; set; }

    [NotLessThan0]
    decimal Price { get; set;}
}


如果您正在使用支持DataAnnotations的东西,您应该能够使用元数据类来包含验证属性:

public class ProductMetadata 
{
    [NotEmpty, NotShorterThan10Characters, NotLongerThan100Characters]
    public string Name { get; set; }

    [NotLessThan0]
    public decimal Price { get; set;}
}

并将其添加到域实体和DTO上的MetadataTypeAttribute中:

[MetadataType(typeof(ProductMetadata))]
public class Product

[MetadataType(typeof(ProductMetadata))]
public class ProductViewModel

这不会与所有验证器一起开箱即用 - 您可能需要扩展您选择的验证框架以实现类似的方法。


我一直在考虑这个问题。 我完全理解布拉德的回答。 但是,我们假设我想使用另一个适用于注释域实体和视图模型的验证框架。

我可以在纸上提出的仍然可以使用属性的唯一解决方案是创建另一个属性,该属性“指向”您正在视图模型中镜像的域实体的属性。 这是一个例子:

// In UI as a view model.
public class UserRegistration {
  [ValidationDependency<Person>(x => x.FirstName)]
  public string FirstName { get; set; }

  [ValidationDependency<Person>(x => x.LastName)]
  public string LastName { get; set; }

  [ValidationDependency<Membership>(x => x.Username)]
  public string Username { get; set; }

  [ValidationDependency<Membership>(x => x.Password)]
  public string Password { get; set; }
}

像xVal这样的框架可以扩展为处理这个新属性并在依赖类的属性上运行验证属性,但是使用视图模型的属性值。 我没有时间把它更多地充实。

有什么想法吗?


验证的目的是确保进入您的应用程序的数据符合某些标准,考虑到这一点,验证属性约束唯一有意义的地方,例如您在此处确定的那些,就是您接受来自不可信的来源(即用户)。

您可以使用“money pattern”之类的内容将验证提升到域类型系统中,并在视图模型中使用这些域类型。 如果您有更复杂的验证(即您表达的业务规则需要比单个属性中表达的知识更多的知识),则这些属于应用更改的域模型上的方法。

简而言之,将数据验证属性放在视图模型上,并将它们从域模型中删除。





dto