Получите значение свойства родительского объекта в дочернем свойстве в контексте проверки

Этот вопрос связан с Asp.net MVC5. Ответ на аналогичный вопрос здесьhttps://stackoverflow.com/questions/7674841/net-mvc3-conditionally-validating-property-what-relies-on-parent-object-proper/

У меня есть следующая модель просмотра:

public class ParentModel
{
    public DateTime EffectiveDate { get; set; }
    public List<ChildModel> Children { get; set; }
    //.....
    //.....
}
public class ChildModel
{
    [DateOfBirthRange(ErrorMessage = "Date of Birth must be within range")]
    public DateTime DateOfBirth { get; set; }
    //.....
    //.....
}

public class DateOfBirthRange : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        return null;
        //here validationContext.ObjectInstance is ChildModel
        //How do i get the Effective Date of ParentModel?
    }
}

ChildModel - это список, и мне нужно проверить DateOfBith всех дочерних моделей относительно значения даты вступления в силу в ParentModel.


person ManojAnavatti    schedule 23.01.2014    source источник


Ответы (3)


Проверка на основе .NET DataAnnotations не предлагает рекурсивную проверку. Однако вы можете расширить его, как описано здесь. При этом вы получаете контроль над тем, как создается ValidationContext (используемый для проверки дочерних объектов).

Итак, в ValidateObjectAttribute упомянутой статьи при создании экземпляра нового ValidationContext в IsValid вместо передачи null в качестве поставщика услуг вы можете передать пользовательский IServiceProvider, который дает вам контекст проверки родителя, и используя его ObjectInstance, вы получаете родительский объект, являющийся подтверждено.

person Dejan    schedule 20.01.2017

Вам нужно иметь свойство навигации в вашем классе ChildModel обратно к его родителю. Затем вы можете сделать что-то вроде следующего:

public override ValidationResult(object value, ValidationContext validationContext)
{
    var childModel= validationContext.ObjectInstance as ChildModel;
    var effectiveDate  = childModel.Parent.EffectiveDate;
    // do your tests against effectiveDate and childModel date
}
person Mashton    schedule 23.01.2014
comment
У ChildModel нет свойства Parent. Мне не нужно, есть ли способ получить ParentModel, который был ModelBinded при отправке на сервер в этом ValidationContext. - person ManojAnavatti; 23.01.2014
comment
Дайте вашей ChildModel свойство навигации, чтобы она могла вернуться к родителю, и да - иначе как вы можете найти родителя? Придать ему это свойство должно быть тривиально. - person Mashton; 23.01.2014
comment
@Mashton Нетривиально вернуть дочерней модели свойство навигации родительской модели, поскольку как это свойство навигации должно заполняться из обратной передачи из формы? - person Sylvia; 22.06.2016

В качестве альтернативы вы можете перенести логику проверки в ParentModel, внедрив в нее IValidatableObject. Возможно, ваше правило применяется не к самим дочерним моделям, а к полному родительскому объекту со всеми его дочерними элементами, поскольку дата вступления в силу является свойством родительского объекта.

public class ParentModel : IValidatableObject
{
    //.....
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var result = new List<ValidationResult>();
        foreach (var child in Children.Where(child => child.DateOfBirth.Date < EffectiveDate.AddYears(-1).Date || child.DateOfBirth.Date > EffectiveDate.Date))
        {
            result.Add(new ValidationResult($"The date of birth {child.DateOfBirth} of child {child.Name} is not between now and a year ago."));
        }

        return result;
    }
}

(при условии правильности даты рождения относительно даты вступления в силу и свойства имени в ChildModel.)

person R. Schreurs    schedule 20.09.2019