ASP.NET MVC: Спеціальна перевірка даних DataAnnotation


110

У мене є Модель з 4 властивостями, які мають тип рядка. Я знаю, що ви можете перевірити довжину одного властивості, використовуючи примітку StringLength. Однак я хочу перевірити довжину чотирьох властивостей разом.

Який спосіб MVC зробити це за допомогою анотації даних?

Я запитую це, тому що я новачок у MVC і хочу зробити це правильно, перш ніж приймати власне рішення.


2
Ви подивилися на перевірку вільної здатності? Він обробляє складні сценарії набагато краще, ніж Анотації даних
levelnis

Погляньте на дуже рекомендовані рішення .... dotnetcurry.com/ShowArticle.aspx?ID=776
Niks

Дякую за відповідь. Я перевіряю валідизацію ваги, ніколи про неї не чув. І Нікс, Дарін в основному виписав те, що пояснила стаття за посиланням, яке ви розмістили. Отже, дякую ... Дивовижні речі!
Danny van der Kraan

Відповіді:


177

Ви можете написати спеціальний атрибут перевірки:

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

і тоді ви можете мати модель перегляду і прикрасити одну з його властивостей:

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

4
Дякую за відповідь, я прийняв вашу відповідь. Відчуйте себе справді збентеженою. Ви виписали все рішення! Хе-хе. Потрібно було лише змінити функцію IsValid, щоб перевірити максимальну довжину. Так це прийняте рішення MVC для подібних проблем?
Danny van der Kraan

7
@DannyvanderKraan, так, це прийнятий спосіб. Звичайно, це гарно так сильно, що я ніколи його не використовую і замість цього використовую FluentValidation.NET для перевірки.
Дарин Димитров

11
Тут: fluentvalidation.codeplex.com . Ви могли б просто написав простий валідатор для моделі уявлення , які могли б виглядати так (один рядок коду): this.RuleFor(x => x.Foo).Must((x, foo) => x.Foo.Length + x.Bar.Length + x.Baz.Length < 20).WithMessage("The combined minimum length of the Foo, Bar and Baz properties should be longer than 20");. А тепер подивіться на код у моїй відповіді, що вам потрібно написати разом із анотаціями до даних, і скажіть, який з них ви віддаєте перевагу. Модель декларативної перевірки дуже погана порівняно з імперативною моделлю.
Дарин Димитров

1
Це трохи пізно, але хтось знає, чи існує інша установка, яку потрібно "включити", щоб дозволити користувацькі анотації даних? Мені відомо про додавання простору імен для ненав’язливих js у файл web.config, але деінде?
Хосе

1
Я шукав це все ранок! Я це застосував, і, на жаль, коли IsValidйого називають " validationContextnull". Будь-яка ідея, що я зробив не так? :-(
Grimm The Opiner

95

Самовивірена модель

Ваша модель повинна реалізувати інтерфейс IValidatableObject. Введіть свій код перевірки в Validateметод:

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

Зверніть увагу: це перевірка на сервері . Це не працює на стороні клієнта. Перевірка буде здійснена лише після надсилання форми.


Дякуємо за відповідь Андрія. Хоча ваше рішення теж спрацювало, я вибираю Даріна, тому що воно більше для багаторазового використання.
Danny van der Kraan

6
повернути прибутковість новий ValidationResult ("Заголовок обов'язковий", "Назва"); буде додано ім'я властивості, корисне для групування помилок перевірки для відображення, якщо це необхідно.
Майк Кінгскотт,

5
Зауважте, що цей метод перевірки викликається лише після того, як всі атрибути перевірки пройшли перевірку.
Педро

3
Це добре працювало для мене, оскільки моя перевірка була дуже специфічною. Додавання спеціального атрибуту було б для мене надмірним, оскільки перевірка не використовувалася повторно.
Steve S

Це те, що я шукаю. Дякую!
Амол

27

ExpressiveAnnotations надає таку можливість:

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

Це геніально! мої молитви отримали відповідь :)
Korayem

Щойно знайшов цю відповідь, і це просто заощадило багато часу. ЕкспресивніАнотації - блискучі!
Бред

10

Щоб покращити відповідь Даріна, це може бути трохи коротше:

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

Модель:

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

Зверніть увагу, що повідомлення про помилку потрібно, інакше помилка буде порожньою.


8

Фон:

Перевірка моделі потрібна для забезпечення достовірності та правильності отриманих даних, які ми отримуємо, щоб ми могли зробити подальшу обробку цими даними. Ми можемо перевірити модель методом дії. Вбудовані атрибути перевірки - Порівняти, Діапазон, Регулярне вираження, Потрібно, StringLength. Однак у нас можуть бути сценарії, в яких нам потрібні атрибути перевірки, відмінні від вбудованих.

Спеціальні атрибути перевірки

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

Щоб створити спеціальний атрибут перевірки, вам доведеться отримати цей клас з 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;
    }
}

Сподіваюся, це допомагає. Ура!

Список літератури


1

Трохи пізно відповісти, але для того, хто шукає. Це можна легко зробити, скориставшись додатковою властивістю з анотацією даних:

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

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

Це все, що теж є насправді. Якщо ви дійсно хочете відобразити і в певному місці помилку перевірки, ви можете додати це у своєму поданні:

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

це може бути корисним, якщо ви хочете зробити локалізацію.

Сподіваюся, це допомагає!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.