有几种方法可以解决这个问题,最适合您的方法取决于以下几点:
IsRegistrationNumberValid
您的方法位于何处以及逻辑是否被移动?
- 您是否正在验证用户输入或域的完整性(您应该同时检查两者,但每个验证将在不同的位置)?
- 个人喜好。
在我看来,您有以下可用选项:
- 在您的控制器操作方法中验证。
- 使用
IValidatableObject
接口进行验证。
- 使用自定义
ValidationAttribute
.
- 在您的服务层中验证。
选项 1:在您的控制器中验证:
首先,您可以简单地验证控制器操作方法中的值并更新ModelState
如下:
[HttpPost]
public ActionResult Create(UserRegistrationViewData model)
{
if (ModelState.IsValid)
{
if (!someObject.IsRegistrationNumberValid(model.value))
{
ModelState.AddModelError("PropertyName", "There is an error..");
Return View()
}
else
{
// Carry out successful action here...
}
}
}
选项2:使用IValidatableObject
接口。
第二种更简洁的方法是IValidatableObject
在 viewModel 上实现接口,以便您可以将逻辑移出控制器:
public class ViewModel : IValidatableObject
{
public int Value { get; set; }
IEnumerable<ValidationResult> IValidatableObject.Validate(ValidationContext validationContext)
{
if (!staticClass.IsRegistrationNumberValid(this.Value))
{
yield return new ValidationResult("An error occured");
}
}
选项 3:创建自定义验证属性。
如前所述,您可以通过从ValidationAttribute
本文中所示的派生来创建自定义验证属性。
接口和自定义验证属性之间的选择IvalidatableObject
通常取决于偏好,但是,接口获胜的一种情况IValidatableObject
是您的验证取决于多个属性(例如检查一个日期是否在另一个之后)。
选项 4:在您的服务层中验证。
最后,如果您的验证依赖于数据库中的其他信息,您可能需要查看本教程关于使用服务层进行验证。这篇文章并不完美(服务和控制器的耦合有点太紧了),但它是一个好的开始,通过一些修改,您可以以非常透明和用户的方式将数据库验证错误(例如主键违规)传递到您的用户界面中-友好的方式。
您最终可能会混合使用选项 2、3 和 4。如果可能的话,您并不想使用第一个选项,因为它会使您的控制器方法更复杂,并且更难以在其他地方重用验证逻辑。
我的建议如下:
- 如果您正在验证用户输入的完整性(例如检查日期格式是否正确),请混合使用
IValidatableObject
接口和ValidationAttribute
类。
- 如果您正在验证域的完整性(确保没有输入重复的实体,或者定义了实体之间的关系),请在服务层中执行验证。