【问题标题】:Command validation using data annotations and DDD "ChangeProperty" methods使用数据注释和 DDD“ChangeProperty”方法进行命令验证
【发布时间】:2015-09-28 12:50:03
【问题描述】:

以下面的简单实体...

public class MyEntity
{
    [MaxLength(100)]
    [Required]
    public string Name { get; private set; }
}

...是否可以读取装饰“名称”属性的数据注释并验证 ChangeName 方法中指定的值,以便可以将 ValidationResults 连接到其他验证结果。我假设如何使用 MethodInfo 或 PropertyInfo 对象?

我有这个,但感觉很笨拙。

    public ValidationResult ChangeName(string value)
    {
        var property = GetType().GetProperty("Name");
        var attribute = property.GetCustomAttributes(typeof(MaxLengthAttribute), true)[0] as MaxLengthAttribute;
        if (attribute == null) return null; //yield break;

        if (value.Length > attribute.Length)
        {
            return new ValidationResult(NameValidation.NameTooLong);
        }

        return null;
    }

我希望能够像这样从我的验证器中的方法调用 ChangeName(value)..

    private IEnumerable<ValidationResult> ValidateMyEntity(MyEntityAddCommand command)
    {
        MyEntity myEntity = new MyEntity();
        yield return myEntity.ChangeName(command.Name);
    }

到目前为止,我读过的大部分内容都说数据注释是针对 CRUD 而不是 DDD,但为什么不使用它们,因为它们是描述验证行为的好方法,并且它将与我的 MVC 视图模型上的数据注释验证一致。 有没有更好或更简洁的方法可以做到这一点?感谢所有建议。

【问题讨论】:

  • @plalx - 所以如果我的理解正确,我应该让我的实体的 ChangeName() 方法抛出一个验证异常,然后我的验证器可以捕捉到它并按照它的需要做?
  • 这个想法是一个无效的命令应该几乎永远不会到达您的域。从这个意义上说,这是一种特殊情况,可以抛出异常。它不应该到达您的域,因为您将在 UI 上进行验证,在那里使用任何很棒的视图模型验证框架都是有意义的。最后,您最终会得到规则的重复,并且在某种程度上是这样,但 UI 通常会收集所有错误并将它们呈现给用户,而域应该尽早抛出并且不关心那个仪式。
  • 在某些情况下,UI 可能无法执行验证,但这些通常更多的是关于命令本身的有效性而不是它的数据成员的有效性(例如,尝试在 5 分钟后修改评论关于 SO)。在这些情况下,我们希望命令能够到达域,我们必须确保返回描述性错误代码,让客户端能够了解发生了什么问题。
  • @plalx +1 表示“返回描述性错误代码”

标签: c# validation domain-driven-design data-annotations command-pattern


【解决方案1】:

我不再追求验证可以(或应该)在一个地方进行的理想。仅在一个地方进行验证是一个好主意,它可以消除代码重复,但我从来没有遇到过千篇一律的问题(它在 95% 的情况下都有效,但是对于那 5% 的情况,它会花费你一天的开发时间来解决应该需要 10 分钟的问题)。有时,验证规则可能会因您正在使用的应用程序的视图或部分而异。现在,我在数据进入我的系统时进行验证,无论是网页表单还是 Web 服务等。我还通过拥有始终有效的域实体来进行验证。

如果使用 MVC,我会将数据注释放在我的视图模型中。如果在 ORM(如 EF 或 NHibernate)上使用,我将我的注释放在我的数据实体上,并将它们限制为被存储库隐藏(我的存储库返回域实体)。

我使我的域实体没有验证类型注释(如果可能,任何注释)。我还确保我的域实体始终有效,并在尝试将我的实体设置为无效状态/值时抛出异常。通过这种方式,它向我发出信号表明出现了问题,不仅仅是在验证方面,而且它告诉我,不知何故,不良数据已经越过了我的第一道防线,我需要修复我的代码。

【讨论】:

  • 很好的建议。谢谢。所以共识是不要继续我的方法,并在实体中保留实体验证并将属性分箱。
  • 我想是的。如果我在做 MVC,我可能会使用属性来验证来自我的视图模型的输入,但通常对于我的域实体,我会尽量避免使用仅在其他层中有意义的属性来装饰它们。当然,编码总是一个很大的权衡,所以如果添加属性可以让您以很少的成本获得巨大的回报,那么它可能是具有成本效益或明智的解决方案。特别是如果应用程序是小型/中型的。但在您的情况下,在入口点完成始终有效的实体和数据验证可能会大大有助于实现良好的验证。
  • 在应用服务层验证命令有意义吗? (除了当然是自我验证的域)。我有一个由 AngularJs 客户端使用的 REST 服务,希望将来有一些本地移动客户端,例如 android 和 ios……请注意,我想自动测试我的应用程序层
猜你喜欢
  • 2015-11-21
  • 1970-01-01
  • 2021-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多