在我们的域中,我们有Student,每个学生都有名字,姓氏和学生编号。学生编号的业务规则是,学生编号可以是1到99999之间的任何数字。由于此验证属于域层,因此我为此编写了一个类,例如;
public class StudentNumber : ValueObject
{
public StudentNumber(int value)
{
if (value <= 0 || value > 99999)
{
throw new ArgumentOutOfRangeException(
nameof(value),
"Student number must be in range of (0,9999]");
}
Value = value;
}
public int Value { get; private set; }
public static implicit operator StudentNumber(int value)
{
return new StudentNumber(value);
}
}
但是,最好在应用程序层验证输入。因此,我最终得到了一个验证类(通过使用FluentValidation库),该类可以在下面找到;
public class CreateStudentCommandValidator : AbstractValidator<CreateStudentCommand>
{
public CreateStudentCommandValidator()
{
RuleFor(m => m.StudentNumber)
.ExclusiveBetween(0, 100000)
.WithMessage(ErrorCodes.InvalidStudentNo);
}
}
在CreateStudentCommand中,StudentNumber属性的数据类型为整数。
此验证器有效,但是违反了DRY规则。由于我在域层和应用程序中都重复了验证逻辑。
问题是;在FluentValidation验证程序类中使用域验证代码的最佳实践是什么?
答案 0 :(得分:0)
这两个数字实际上处于不同的模型中-请求模型和域模型。重新阅读问题和原始答案时,我认为我在这里看到了不匹配的地方。
前端验证应限于基本数据类型。如果您希望使用整数,请确保呼叫者发送了整数,日期是日期,字符串是字符串。这是控制器(或直接从用户那里收到请求的任何人)的责任。如果用户发送无效的整数,则在此级别将拒绝该整数。这里没有进行范围检查,我们只是检查以确保请求格式正确。
然后,控制器创建命令。该命令的作用是将用户的需求传达给域逻辑,该域逻辑执行业务逻辑来执行该需求。我们假设用户确实确实想创建一个具有给定编号的学生,因此命令应将此要求传达给域,即命令中不应进行范围验证。通常仅使用适当类型的构造函数参数来完成命令验证。
“域”逻辑尝试执行用户的需求并创建一个具有无效编号的新学生。域确定这不是一个有效的数字,并在此级别上引发异常,从而使命令执行失败。控制器感测到失败的命令执行,并向调用者返回适当的失败(或者,如果命令执行是异步的,则以适当的方式处理错误)。
您最初的直觉是正确的,因为您违反了DRY。可以通过更改业务规则以扩大范围来证明这一点。单个业务规则更改将需要更改两个代码,从而证明您在重复自己。