危险......危险史密斯博士......前面的哲学文章
这篇文章的目的是确定将验证逻辑放在我的域实体之外(实际上是聚合根)是否实际上给了我更大的灵活性或它是神风代码
基本上我想知道是否有更好的方法来验证我的域实体.这就是我计划这样做的方式,但我希望你的意见
我考虑的第一种方法是:
class Customer : EntityBase<Customer>
{
public void ChangeEmail(string email)
{
if(string.IsNullOrWhitespace(email)) throw new DomainException(“...”);
if(!email.IsEmail()) throw new DomainException();
if(email.Contains(“@mailinator.com”)) throw new DomainException();
}
}
Run Code Online (Sandbox Code Playgroud)
我实际上不喜欢这种验证,因为即使我将验证逻辑封装在正确的实体中,这也违反了Open/Close原则(Open for extension但Close for modification)我发现违反这个原则,代码维护就变成了当应用程序在复杂性中成长时,真正的痛苦.为什么?因为域规则的变化比我们想要承认的更频繁,并且如果规则被隐藏并嵌入到这样的实体中,它们很难测试,难以阅读,难以维护但是我不喜欢这个的真正原因方法是:如果验证规则发生变化,我必须来编辑我的域实体.这是一个非常简单的例子,但在RL中验证可能更复杂
因此遵循Udi Dahan的哲学,明确角色,以及Eric Evans在蓝皮书中的推荐,接下来的尝试是实现规范模式,就像这样
class EmailDomainIsAllowedSpecification : IDomainSpecification<Customer>
{
private INotAllowedEmailDomainsResolver invalidEmailDomainsResolver;
public bool IsSatisfiedBy(Customer customer)
{
return !this.invalidEmailDomainsResolver.GetInvalidEmailDomains().Contains(customer.Email);
}
}
Run Code Online (Sandbox Code Playgroud)
但后来我才意识到,为了遵循这种方法,我必须首先改变我的实体,以便传递值为valdiated,在这种情况下是电子邮件,但是改变它们会导致我的域事件被触发,我不想直到新电子邮件有效为止
因此,在考虑了这些方法后,我推出了这个方法,因为我要实现CQRS架构:
class EmailDomainIsAllowedValidator : IDomainInvariantValidator<Customer, ChangeEmailCommand>
{
public void IsValid(Customer entity, ChangeEmailCommand command)
{
if(!command.Email.HasValidDomain()) throw new DomainException(“...”);
} …Run Code Online (Sandbox Code Playgroud) 我正在使用FluentValidation来验证我的服务操作.我的代码看起来像:
using FluentValidation;
IUserService
{
void Add(User user);
}
UserService : IUserService
{
public void Add(User user)
{
new UserValidator().ValidateAndThrow(user);
userRepository.Save(user);
}
}
Run Code Online (Sandbox Code Playgroud)
UserValidator实现FluentValidation.AbstractValidator.
DDD表示域层必须与技术无关.
我正在做的是使用验证框架而不是自定义异常.
将验证框架放在域层中是一个坏主意吗?
c# architecture domain-driven-design repository fluentvalidation