c# - 如何在 ASP.NET 中干净地共享数据模型、ViewModel 和 DTO 的自定义验证器 (ValidationAttribute)
问题描述
我正在做一个 ASP.NET MVC 课程。我正在使用 ASP.NET WebAPI 2 构建一个 REST Web API。该应用程序还包含标准的 MVC 5 视图。我正在使用 DTO(数据传输对象)将 API 与数据模型分离。我已经创建了一个自定义 ValidationAttribute,我已将其应用于我的数据模型中的属性,并且我想对我的 DTO 上的属性以及在 MVC 视图中使用的属性 ViewModel 使用相同的 Validation 属性。
这需要将其ValidationContext.ObjectInstance
转换为正确的类型。我找到了一个简单的解决方案,但我觉得它不是很优雅,我想知道是否有更好的方法来做到这一点。
我正在谈论的特定 ValidationAttribute 和属性:
[Min18YearsIfAMember]
public DateTime? DateOfBirth { get; set; }
在解决方案的上下文中(为简洁起见,删除了一些细节,包括 CustomerViewModel):
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public MembershipType MembershipType { get; set; }
public byte MembershipTypeId { get; set; }
[Min18YearsIfAMember]
public DateTime? DateOfBirth { get; set; }
}
public class CustomerDto
{
public int Id { get; set; }
public string Name { get; set; }
public byte MembershipTypeId { get; set; }
[Min18YearsIfAMember]
public DateTime? DateOfBirth { get; set; }
}
public class Min18YearsIfAMemberAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
// Check it here
var customer = validationContext.ObjectInstance as Customer;
if (customer != null)
return DoValidation(customer.MembershipTypeId, customer.DateOfBirth);
// Check it here
var customerVm = validationContext.ObjectInstance as CustomerViewModel;
if (customerVm != null)
return DoValidation(customerVm.MembershipTypeId, customerVm.DateOfBirth);
// Yes I should probably check it here too
var customerDto = validationContext.ObjectInstance as CustomerDto;
return DoValidation(customerDto.MembershipTypeId, customerDto.DateOfBirth);
}
private ValidationResult DoValidation( int membershipTypeId, DateTime? DateOfBirth)
{
// Do the validation....
}
}
它是可读的,但我觉得像这样检查每个可能的情况很难看ValidationContext.ObjectInstance as Customer
。
有没有更好的办法?
解决方案
在数据注释属性中,您可以在附加属性时指定依赖属性,并使用它可以验证对象类型的属性:
public class Min18YearsIfAMemberAttribute : ValidationAttribute
{
private string _dependentProperty { get; set; }
public Min18YearsIfAMemberAttribute(string dependentProperty)
{
this._dependentProperty = dependentProperty;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var field = validationContext.ObjectType.GetProperty(_dependentProperty);
if (field != null)
{
var dependentValue = (byte)field.GetValue(validationContext.ObjectInstance, null);
return DoValidation(dependentValue, (DateTime?)value);
}
else
{
return new ValidationResult("<Your message here>");
}
}
private ValidationResult DoValidation( int membershipTypeId, DateTime? DateOfBirth)
{
// Do the validation....
}
现在在附加属性时,我们指定依赖属性名称[Min18YearsIfAMember("MembershipTypeId")
。
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public MembershipType MembershipType { get; set; }
public byte MembershipTypeId { get; set; }
[Min18YearsIfAMember(nameof(MembershipTypeId))]
public DateTime? DateOfBirth { get; set; }
}
推荐阅读
- java - 如何使用带有服务器 IP 的 JDBC 连接到 Mongodb?
- c - 在 C 中声明匿名结构的局部 const 变量
- bash - 查找包含至少三个字母实例的单词
- reactjs - React Hook "useDispatch" 不能在顶层调用。必须在 React 函数组件或自定义 React Hook 函数中调用 React Hooks
- arrays - Laravel:使用数组显示数据 WHEREIN 'Imploded Id'
- ios - 如何知道 AnchorEntity 动作序列何时完成?
- html - Bootstrap 将文本与复选框对齐
- visual-studio-code - 什么是 Visual Studio Code 的 Code Review 扩展
- css - 在地图中使用三元运算符,我想使用它来更改材料表的列宽
- amazon-web-services - DynamDB 在两个字段中保存自动生成的值