简体   繁体   English

如何在 ASP.NET 中干净地共享数据 model、ViewModel 和 DTO 的自定义验证器 (ValidationAttribute)

[英]How can I cleanly share a Custom Validator (ValidationAttribute) for a data model, a ViewModel, and a DTO in ASP.NET

I'm doing a ASP.NET MVC course.我正在学习 ASP.NET MVC 课程。 I'm building a REST Web API using ASP.NET WebAPI 2. The application also contains standard MVC 5 views.我正在使用 Z9E0DA8438E1E38A1C30F4B76CE8Z API 标准构建 REST Web API 标准还包含应用程序。 I'm using DTOs (Data Transfer Objects) to decouple the API from the data model.我正在使用 DTO(数据传输对象)将 API 与数据 model 分离。 I've made a custom ValidationAttribute that I have applied to a property in my data model, and I'd like to use the same Validation attribute for a property on my DTO as well as a property ViewModel used in an MVC view.我已经创建了一个自定义 ValidationAttribute,我已将其应用于我的数据 model 中的一个属性,并且我想对我的 DTO 上的属性以及在 MVC 视图中使用的属性 ViewModel 使用相同的 Validation 属性。

This requires casting the ValidationContext.ObjectInstance to the right type.这需要将ValidationContext.ObjectInstance转换为正确的类型。 I have found a simple solution, but I don't find it very elegant, and I'd like to know if there is a better way to do this.我找到了一个简单的解决方案,但我觉得它不是很优雅,我想知道是否有更好的方法来做到这一点。

The specific ValidationAttribute and property I'm talking about:我正在谈论的特定 ValidationAttribute 和属性:

[Min18YearsIfAMember]
public DateTime? DateOfBirth { get; set; }

In the context of the solution (some details removed for brevity including CustomerViewModel):在解决方案的上下文中(为简洁起见,删除了一些细节,包括 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....
    }
}

It's readable, but I find it ugly having to check each possible case like so ValidationContext.ObjectInstance as Customer .它是可读的,但是我发现必须检查每个可能的情况,例如ValidationContext.ObjectInstance as Customer ,这很难看。

Is there a better way?有没有更好的办法?

In the data annotation attribute, you can specify the dependent property while attaching the attribute and using that you can validate the property for object types:在数据注释属性中,您可以在附加属性时指定依赖属性,并使用它可以验证 object 类型的属性:

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....
    }

Now while attaching the attribute we specify the dependent property name [Min18YearsIfAMember("MembershipTypeId") .现在在附加属性时,我们指定依赖属性名称[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; }
}  

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 ASP.NET MVC:模型─添加自定义ValidationAttribute - ASP.NET MVC : Model ─ Adding custom ValidationAttribute 如何在 ASP.NET Core 3.0 中使用 ValidationAttribute 验证多个操作参数 - How can I validate multiple action parameters with ValidationAttribute in ASP.NET Core 3.0 如何使用 Asp.Net Core ViewModel 显示模型数据 - How to display model data using Asp.Net Core ViewModel ASP.Net MVC 4 Custom ValidationAttribute依赖注入 - ASP.Net MVC 4 Custom ValidationAttribute Dependency Injection MVC asp.net中的DTO是否可以自行加载数据 - Can DTO in MVC asp.net load data by itself 如何为外部库中定义的 model 编写 ASP.NET 自定义验证器 - How to write an ASP.NET custom validator for a model defined in an external library 如何在Asp.net ValidationAttribute中将HTML标记列入白名单 - How to whitelist html tags in Asp.net ValidationAttribute 我如何将现有模型(设备)数据附加到MVC ASP.NET中的另一个模型(用户)数据 - How can i attach existing model(device) data to another model(user) data in mvc asp.net 如何在ASP.NET Core中将DataAnnotations从模型传输到ViewModel? - How to transfer DataAnnotations from model to viewModel in asp.net core? 如何创建可用于2个或更多字段的asp.net MVC自定义模型验证 - How can I create an asp.net MVC custom model validation that is working with 2 or more fields
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM