ASP.NET MVC3 условная проверка вложенности модели для EditorTemplate

Предположим, у вас есть viewModel:

public class CreatePersonViewModel
{
    [Required]
    public bool HasDeliveryAddress {get;set;}

    // Should only be validated when HasDeliveryAddress is true
    [RequiredIf("HasDeliveryAddress", true)]
    public Address Address { get; set; }
}

И модель Address будет выглядеть так:

public class Address : IValidatableObject
{
    [Required]
    public string City { get; set; }
    [Required]        
    public string HouseNr { get; set; }
    [Required]
    public string CountryCode { get; set; }
    [Required]
    public string FirstName { get; set; }
    [Required]
    public string LastName { get; set; }
    [Required]
    public string ZipCode { get; set; }
    [Required]
    public string Street { get; set; }

    #region IValidatableObject Members

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        string[] requiredFields;
        var results = new List<ValidationResult>();

        // some custom validations here (I removed them to keep it simple)

        return results;
    }

    #endregion
}

Некоторые предложили бы создать модель представления для Address и добавить туда некоторую пользовательскую логику, но мне нужен экземпляр Address перейти к моему EditorTemplate для адреса.

Основная проблема здесь заключается в том, что проверка адреса выполняется до проверки моей модели PersonViewModel, поэтому я не могу предотвратить ее.

Примечание: RequiredIfAttribute - это пользовательский атрибут, который делает то, что я хочу, для простых типов.

2 ответа

Решение

Было бы легко, если бы вы использовали FluentValidation.NET вместо DataAnnotations или IValidatableObject, которые довольно сильно ограничивают возможности проверки в сложных сценариях:

public class CreatePersonViewModelValidator : AbstractValidator<CreatePersonViewModel>
{
    public CreatePersonViewModelValidator()
    {
        RuleFor(x => x.Address)
            .SetValidator(new AddressValidator())
            .When(x => x.HasDeliveryAddress);
    }
}

У Саймона Инса есть альфа-версия Mvc.ValidationToolkit, которая, кажется, может делать то, что вы хотите.

Обновить
Насколько я понимаю, "проблема" заключается в классе DefaultModelBinder, который проверяет вашу модель на основе того, что, если он находит атрибут проверки, он спрашивает, является ли значение допустимым (на самом деле вполне разумным!), У него нет понятия иерархии., Для поддержки требуемой функциональности вам нужно написать пользовательское связующее звено модели, которое связывает, а затем проверяет, если необходимо, как определено вашей декларативной разметкой.
Если вы пишете такой класс, он может быть хорошим кандидатом на фьючерсы MVC.

Другие вопросы по тегам