使用数据注释和DDD"ChangeProperty"方法进行命令验证

Dib*_*Dib 4 c# validation domain-driven-design command-pattern data-annotations

以下简单的实体...

public class MyEntity
{
    [MaxLength(100)]
    [Required]
    public string Name { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)

...是否可以读取正在装饰"Name"属性的数据注释并验证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;
    }
Run Code Online (Sandbox Code Playgroud)

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

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

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

Adr*_*ips 6

我不再追求验证可以(或应该)在一个地方发生的理想.只在一个地方进行验证是一个好主意,它会删除代码重复,但是如果没有遇到一个通用的问题(95%的情况下它可以工作,我从来没有能够实现它)但对于那个没有它的5%,你需要花费一天的时间来解决需要10分钟的事情.有时,验证规则可能会根据您使用的应用程序的视图或部分内容而有所不同.现在我验证数据进入我的系统,无论是网页表单还是网络服务等.我还通过拥有始终有效的域实体进行验证.

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

我保持我的域实体没有验证类型注释(如果可能的话,任何注释).我还确保我的域实体始终有效,并在尝试将我的实体设置为无效状态/值时抛出异常.这样它就向我发出了一些错误的信号,而不仅仅是在验证意义上,但它告诉我,不知何故,糟糕的数据使它超越了我的第一道防线并且我需要修复我的代码.

  • 我认同.如果我正在进行MVC,我可能会使用这些属性来验证来自我的视图模型的输入,但通常对于我的域实体,我尽量避免使用仅在其他层中具有意义的属性来装饰它们.当然,编码总是一个很大的权衡,所以如果添加属性可以为您带来巨大的回报而且成本很低,那么它可能是具有成本效益或合理的解决方案.特别是如果应用是小型/中型的.但在您的情况下,始终有效的实体和在入口点完成的数据验证可能会对实现良好的验证大有帮助. (2认同)