ASP.NET MVC: Validación personalizada mediante anotación de datos

Resuelto Danny van der Kraan asked hace 11 años • 6 respuestas

Tengo un Modelo con 4 propiedades que son de tipo cadena. Sé que puedes validar la longitud de una sola propiedad usando la anotación StringLength. Sin embargo, quiero validar la longitud de las 4 propiedades combinadas.

¿Cuál es la forma MVC de hacer esto con la anotación de datos?

Pregunto esto porque soy nuevo en MVC y quiero hacerlo de la manera correcta antes de crear mi propia solución.

Danny van der Kraan avatar Apr 19 '13 15:04 Danny van der Kraan
Aceptado

Podrías escribir un atributo de validación personalizado:

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

y luego podrías tener un modelo de vista y decorar una de sus propiedades con él:

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; }
}
Darin Dimitrov avatar Apr 19 '2013 08:04 Darin Dimitrov

Modelo autovalidado

Su modelo debe implementar una interfaz IValidatableObject. Pon tu código de validación en el Validatemétodo:

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) });
    }
}

Tenga en cuenta: esta es una validación del lado del servidor . No funciona del lado del cliente. Su validación se realizará solo después del envío del formulario.

Andrei avatar Apr 19 '2013 08:04 Andrei

ExpressiveAnnotations le ofrece esa posibilidad:

[Required]
[AssertThat("Length(FieldA) + Length(FieldB) + Length(FieldC) + Length(FieldD) > 50")]
public string FieldA { get; set; }
jwaliszko avatar Jul 17 '2014 21:07 jwaliszko

Para mejorar la respuesta de Darin, puede ser un poco más corta:

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);
    }
}

Modelo:

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

Tenga en cuenta que se requiere un mensaje de error; de lo contrario, el error estará vacío.

Jamie avatar Nov 12 '2017 15:11 Jamie