ASP。NET MVC:通过DataAnnotation进行自定义验证

时间:2021-11-10 15:54:56

I have a Model with 4 properties which are of type string. I know you can validate the length of a single property by using the StringLength annotation. However I want to validate the length of the 4 properties combined.

我有一个具有4个属性的模型,它们是string类型的。我知道您可以使用StringLength注释来验证单个属性的长度。但是我想验证这4个属性组合的长度。

What is the MVC way to do this with data annotation?

用数据注释来实现这一点的MVC方法是什么?

I'm asking this because I'm new to MVC and want to do it the correct way before making my own solution.

我问这个是因为我是MVC的新手,我想在做我自己的解决方案之前用正确的方式来做。

6 个解决方案

#1


152  

You could write a custom validation attribute:

您可以编写自定义验证属性:

public class CombinedMinLengthAttribute: ValidationAttribute
{
    public CombinedMinLengthAttribute(int minLength, params string[] propertyNames)
    {
        this.PropertyNames = propertyNames;
        this.MinLength = minLength;
    }

    public string[] PropertyNames { get; private set; }
    public int MinLength { get; private set; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var properties = this.PropertyNames.Select(validationContext.ObjectType.GetProperty);
        var values = properties.Select(p => p.GetValue(validationContext.ObjectInstance, null)).OfType<string>();
        var totalLength = values.Sum(x => x.Length) + Convert.ToString(value).Length;
        if (totalLength < this.MinLength)
        {
            return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
        }
        return null;
    }
}

and then you might have a view model and decorate one of its properties with it:

然后你可能有一个视图模型用它来装饰它的一个属性:

public class MyViewModel
{
    [CombinedMinLength(20, "Bar", "Baz", ErrorMessage = "The combined minimum length of the Foo, Bar and Baz properties should be longer than 20")]
    public string Foo { get; set; }
    public string Bar { get; set; }
    public string Baz { get; set; }
}

#2


81  

Self validated model

Your model should implement an interface IValidatableObject. Put your validation code in Validate method:

您的模型应该实现一个接口IValidatableObject。将验证代码放在Validate method中:

public class MyModel : IValidatableObject
{
    public string Title { get; set; }
    public string Description { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Title == null)
            yield return new ValidationResult("*", new [] { nameof(Title) });

        if (Description == null)
            yield return new ValidationResult("*", new [] { nameof(Description) });
    }
}

Please notice: this is a server-side validation. It doesn't work on client-side. You validation will be performed only after form submission.

请注意:这是一个服务器端验证。它不能在客户端上工作。只有在提交表单之后才会执行验证。

#3


15  

ExpressiveAnnotations gives you such a possibility:

expressiveannotation给你提供了这样一种可能性:

[Required]
[AssertThat("Length(FieldA) + Length(FieldB) + Length(FieldC) + Length(FieldD) > 50")]
public string FieldA { get; set; }

#4


6  

Background:

背景:

Model validations are required for ensuring that the received data we receive is valid and correct so that we can do the further processing with this data. We can validate a model in an action method. The built-in validation attributes are Compare, Range, RegularExpression, Required, StringLength. However we may have scenarios wherein we required validation attributes other than the built-in ones.

需要进行模型验证,以确保接收到的数据是有效和正确的,以便我们可以对这些数据进行进一步处理。我们可以在操作方法中验证模型。内置的验证属性是Compare, Range, RegularExpression, Required, StringLength。但是,我们可能会遇到需要验证属性而不是内置属性的场景。

Custom Validation Attributes

自定义验证属性

public class EmployeeModel 
{
    [Required]
    [UniqueEmailAddress]
    public string EmailAddress {get;set;}
    public string FirstName {get;set;}
    public string LastName {get;set;}
    public int OrganizationId {get;set;}
}

To create a custom validation attribute, you will have to derive this class from ValidationAttribute.

要创建自定义验证属性,您必须从ValidationAttribute派生该类。

public class UniqueEmailAddress : ValidationAttribute
{
    private IEmployeeRepository _employeeRepository;
    [Inject]
    public IEmployeeRepository EmployeeRepository
    {
        get { return _employeeRepository; }
        set
        {
            _employeeRepository = value;
        }
    }
    protected override ValidationResult IsValid(object value,
                        ValidationContext validationContext)
    {
        var model = (EmployeeModel)validationContext.ObjectInstance;
        if(model.Field1 == null){
            return new ValidationResult("Field1 is null");
        }
        if(model.Field2 == null){
            return new ValidationResult("Field2 is null");
        }
        if(model.Field3 == null){
            return new ValidationResult("Field3 is null");
        }
        return ValidationResult.Success;
    }
}

Hope this helps. Cheers !

希望这个有帮助。干杯!

References

引用

#5


3  

To improve Darin's answer, it can be bit shorter:

为了改进达林的答案,可以缩短一点:

public class UniqueFileName : ValidationAttribute
{
    private readonly NewsService _newsService = new NewsService();

    public override bool IsValid(object value)
    {
        if (value == null) { return false; }

        var file = (HttpPostedFile) value;

        return _newsService.IsFileNameUnique(file.FileName);
    }
}

Model:

模型:

[UniqueFileName(ErrorMessage = "This file name is not unique.")]

Do note that an error message is required, otherwise the error will be empty.

请注意,需要一条错误消息,否则错误将为空。

#6


1  

A bit late to answer, but for who is searching. You can easily do this by using an extra property with the data annotation:

回答有点晚,但谁在搜索。您可以通过在数据注释中使用一个额外的属性来轻松做到这一点:

public string foo { get; set; }
public string bar { get; set; }

[MinLength(20, ErrorMessage = "too short")]
public string foobar 
{ 
    get
    {
        return foo + bar;
    }
}

That's all that is too it really. If you really want to display in a specific place the validation error as well, you can add this in your view:

这就是我想说的。如果您真的想在特定的位置显示验证错误,您可以在您的视图中添加这个:

@Html.ValidationMessage("foobar", "your combined text is too short")

doing this in the view can come in handy if you want to do localization.

如果您想要进行本地化,那么在视图中执行此操作将非常有用。

Hope this helps!

希望这可以帮助!

#1


152  

You could write a custom validation attribute:

您可以编写自定义验证属性:

public class CombinedMinLengthAttribute: ValidationAttribute
{
    public CombinedMinLengthAttribute(int minLength, params string[] propertyNames)
    {
        this.PropertyNames = propertyNames;
        this.MinLength = minLength;
    }

    public string[] PropertyNames { get; private set; }
    public int MinLength { get; private set; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var properties = this.PropertyNames.Select(validationContext.ObjectType.GetProperty);
        var values = properties.Select(p => p.GetValue(validationContext.ObjectInstance, null)).OfType<string>();
        var totalLength = values.Sum(x => x.Length) + Convert.ToString(value).Length;
        if (totalLength < this.MinLength)
        {
            return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
        }
        return null;
    }
}

and then you might have a view model and decorate one of its properties with it:

然后你可能有一个视图模型用它来装饰它的一个属性:

public class MyViewModel
{
    [CombinedMinLength(20, "Bar", "Baz", ErrorMessage = "The combined minimum length of the Foo, Bar and Baz properties should be longer than 20")]
    public string Foo { get; set; }
    public string Bar { get; set; }
    public string Baz { get; set; }
}

#2


81  

Self validated model

Your model should implement an interface IValidatableObject. Put your validation code in Validate method:

您的模型应该实现一个接口IValidatableObject。将验证代码放在Validate method中:

public class MyModel : IValidatableObject
{
    public string Title { get; set; }
    public string Description { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Title == null)
            yield return new ValidationResult("*", new [] { nameof(Title) });

        if (Description == null)
            yield return new ValidationResult("*", new [] { nameof(Description) });
    }
}

Please notice: this is a server-side validation. It doesn't work on client-side. You validation will be performed only after form submission.

请注意:这是一个服务器端验证。它不能在客户端上工作。只有在提交表单之后才会执行验证。

#3


15  

ExpressiveAnnotations gives you such a possibility:

expressiveannotation给你提供了这样一种可能性:

[Required]
[AssertThat("Length(FieldA) + Length(FieldB) + Length(FieldC) + Length(FieldD) > 50")]
public string FieldA { get; set; }

#4


6  

Background:

背景:

Model validations are required for ensuring that the received data we receive is valid and correct so that we can do the further processing with this data. We can validate a model in an action method. The built-in validation attributes are Compare, Range, RegularExpression, Required, StringLength. However we may have scenarios wherein we required validation attributes other than the built-in ones.

需要进行模型验证,以确保接收到的数据是有效和正确的,以便我们可以对这些数据进行进一步处理。我们可以在操作方法中验证模型。内置的验证属性是Compare, Range, RegularExpression, Required, StringLength。但是,我们可能会遇到需要验证属性而不是内置属性的场景。

Custom Validation Attributes

自定义验证属性

public class EmployeeModel 
{
    [Required]
    [UniqueEmailAddress]
    public string EmailAddress {get;set;}
    public string FirstName {get;set;}
    public string LastName {get;set;}
    public int OrganizationId {get;set;}
}

To create a custom validation attribute, you will have to derive this class from ValidationAttribute.

要创建自定义验证属性,您必须从ValidationAttribute派生该类。

public class UniqueEmailAddress : ValidationAttribute
{
    private IEmployeeRepository _employeeRepository;
    [Inject]
    public IEmployeeRepository EmployeeRepository
    {
        get { return _employeeRepository; }
        set
        {
            _employeeRepository = value;
        }
    }
    protected override ValidationResult IsValid(object value,
                        ValidationContext validationContext)
    {
        var model = (EmployeeModel)validationContext.ObjectInstance;
        if(model.Field1 == null){
            return new ValidationResult("Field1 is null");
        }
        if(model.Field2 == null){
            return new ValidationResult("Field2 is null");
        }
        if(model.Field3 == null){
            return new ValidationResult("Field3 is null");
        }
        return ValidationResult.Success;
    }
}

Hope this helps. Cheers !

希望这个有帮助。干杯!

References

引用

#5


3  

To improve Darin's answer, it can be bit shorter:

为了改进达林的答案,可以缩短一点:

public class UniqueFileName : ValidationAttribute
{
    private readonly NewsService _newsService = new NewsService();

    public override bool IsValid(object value)
    {
        if (value == null) { return false; }

        var file = (HttpPostedFile) value;

        return _newsService.IsFileNameUnique(file.FileName);
    }
}

Model:

模型:

[UniqueFileName(ErrorMessage = "This file name is not unique.")]

Do note that an error message is required, otherwise the error will be empty.

请注意,需要一条错误消息,否则错误将为空。

#6


1  

A bit late to answer, but for who is searching. You can easily do this by using an extra property with the data annotation:

回答有点晚,但谁在搜索。您可以通过在数据注释中使用一个额外的属性来轻松做到这一点:

public string foo { get; set; }
public string bar { get; set; }

[MinLength(20, ErrorMessage = "too short")]
public string foobar 
{ 
    get
    {
        return foo + bar;
    }
}

That's all that is too it really. If you really want to display in a specific place the validation error as well, you can add this in your view:

这就是我想说的。如果您真的想在特定的位置显示验证错误,您可以在您的视图中添加这个:

@Html.ValidationMessage("foobar", "your combined text is too short")

doing this in the view can come in handy if you want to do localization.

如果您想要进行本地化,那么在视图中执行此操作将非常有用。

Hope this helps!

希望这可以帮助!