Ненавязчивая проверка сложных моделей представлений с плавной проверкой — MVC3

Я пытаюсь понять, почему мой FluentValidation не выполняет ненавязчивую проверку некоторых свойств моей модели представления.

Я установил через NuGet пакет FluentValidation для MVC3:

  Install-Package FluentValidation.MVC3

Результаты:

<package id="FluentValidation" version="5.0.0.1" targetFramework="net45" />
<package id="FluentValidation.MVC3" version="5.0.0.1" targetFramework="net45" />

Свойства, которые не проходят проверку, являются некоторыми членами объекта класса Guitar, объявленного в моей модели представления. Свойство Guitar.ProductionYear получает ненавязчивый код проверки, а два других свойства объекта Guitar — нет.

public Guitar Guitar1 { get; set; }
public Guitar Guitar2 { get; set; }
public Guitar Guitar3 { get; set; }

Я читал документы FluentValidation, а теперь конкретно об ограничениях, касающихся проверки списков FluentValidation на стороне клиента, но это не список, поэтому я надеюсь, что кто-то увидит, что не так, и/или предложит несколько предложений.

Я также пытался использовать собственный валидатор объектов Guitar, но все равно получаю те же результаты.

Observations

  • Проверка на стороне клиента создается и срабатывает для свойств FirstName, LastName, Phone и Email.

  • Я заметил, что ModelState недействителен для этих объектов, когда они не заполнены пользователем, но я не знаю, почему проверка на стороне клиента не создается и впоследствии не срабатывает.

  • В сгенерированном HTML-коде формы для объектов Guitar отсутствуют ненавязчивые атрибуты проверки. Другие свойства, такие как Имя, Фамилия, Электронная почта и Телефон, проверяются нормально.
  • Пример

        <!-- Unobtrusive JS generated-->
            <input type="text" value="" name="FirstName" id="FirstName" data-val-required="'First Name' must not be empty." data-val="true" class="input-validation-error">
            <div class="messageBottom"> 
                    <span data-valmsg-replace="true" data-valmsg-for="FirstName" class="field-validation-error"><span for="FirstName" generated="true" class="">'First Name' must not be empty.</span>
       </span>
     </div>
    
        <!-- Unobtrusive JS Partially generated for Guitar object-->
       <input type="text" value="" name="Guitar.Make" id="Guitar_Make" placeholder="Make">
            <div class="messageBottom">
            <span data-valmsg-replace="true" data-valmsg-for="Guitar1.Make" class="field-validation-valid"></span>
            </div>
    
            <input type="text" value="" name="Guitar1.Model" id="Guitar1_Model" placeholder="Model">
            <div class="messageBottom">
                <span data-valmsg-replace="true" data-valmsg-for="Guitar1.Model" class="field-validation-valid"></span>
            </div>
    
            <input type="text" value="" name="Guitar1.ProductionYear" id="Guitar1_ProductionYear" data-val-number="The field ProductionYear must be a number." data-val="true" placeholder="Production Year" class="valid">
            <div class="messageBottom">
            <span data-valmsg-replace="true" data-valmsg-for="Guitar1.ProductionYear" class="field-validation-valid">
            </span>
            </div>
    

    Спасибо

    Global.asax.cs

    FluentValidationModelValidatorProvider.Configure();
    

    Модель просмотра

    [FluentValidation.Attributes.Validator(typeof(CustomerViewModelValidator))]
    public class CustomerViewModel
    {
        [Display(Name = "First Name")]
        public string FirstName { get; set; }
    
        [Display(Name = "Last Name")]
        public string LastName { get; set; }
    
        [Display(Name = "Phone")]
        public string Phone { get; set; }
    
        [Display(Name = "Email")]
        public string EmailAddress { get; set; }
    
        [Display(Name = "Guitar 1")]
        public Guitar Guitar1 { get; set; }
    
        [Display(Name = "Guitar 2")]
        public Guitar Guitar2 { get; set; }
    
        [Display(Name = "Guitar 3")]
        public Guitar Guitar3 { get; set; }
    }
    

    Валидатор настраиваемых объектов гитары

    public class GuitarValidator : AbstractValidator<Guitar>
    {
        public GuitarValidator()
        {
            RuleFor(x => x.Make).NotEmpty();
            RuleFor(x => x.Model).NotEmpty();
            RuleFor(x => x.ProductionYear).NotEmpty();
        }
    }
    

    Валидатор модели просмотра

    public class CustomerViewModelValidator : AbstractValidator<CustomerViewModel>
    {
        public CustomerViewModelValidator()
        {
            RuleFor(x => x.FirstName).NotNull();
            RuleFor(x => x.LastName).NotNull();
            RuleFor(x => x.Phone).NotNull();
            RuleFor(x => x.EmailAddress).NotNull();
    
            //1st Guitar Object is Required
            RuleFor(x => x.Guitar).SetValidator(new GuitarValidator());
    
    
    
        }
    }
    

    Вид

    <!-- Guitar Object #1 -->
         <div id="cosponsorsTemplate_1">
                <div class="formColumn1">@Html.LabelFor(x=>x.Guitar1)</div>
                <div class="formColumn2">@Html.TextBoxFor(x => x.Guitar1.Make, new { Placeholder = "Make" })
                    <div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar1.Make)</div>
                </div>
                <div class="formColumn3">@Html.TextBoxFor(x => x.Guitar1.Model, new { Placeholder = "Model" })
                    <div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar1.Model)</div>
                </div>
                <div class="formColumn4">@Html.TextBoxFor(x =>x.Guitar1.ProductionYear, new { Placeholder = "Production Year" })
                    <div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar1.ProductionYear)</div>
                    <a class="icon delete" data-delete-id="1">Delete</a>
                </div>
            </div>
    
       <!-- Guitar Object #2 -->
            <div id="cosponsorsTemplate_2">
                <div class="formColumn1">@Html.LabelFor(x=>x.Guitar2)</div>
                <div class="formColumn2">@Html.TextBoxFor(x => x.Guitar2.Make, new { Placeholder = "Make" })
                    <div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar2.Make)</div>
                </div>
                <div class="formColumn3">@Html.TextBoxFor(x => x.Guitar2.Model, new { Placeholder = "Model" })
                    <div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar2.Model)</div>
                </div>
                <div class="formColumn4">@Html.TextBoxFor(x => x.Guitar2.ProductionYear, new { Placeholder = "Production Year" })
                    <div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar2.ProductionYear)</div>
                    <a class="icon delete" data-delete-id="2">Delete</a>
                </div>
            </div>
    
        <!-- Guitar Object #3 -->
            <div id="cosponsorsTemplate_3">
                <div class="formColumn1">@Html.LabelFor(x=>x.Guitar3)</div>
                <div class="formColumn2">@Html.TextBoxFor(x => x.Guitar3.Make, new { Placeholder = "Make" })
                    <div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar3.Make)</div>
                </div>
                <div class="formColumn3">@Html.TextBoxFor(x => x.Guitar3.Model, new { Placeholder = "Model" })
                    <div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar3.Model)</div>
                </div>
                <div class="formColumn4">@Html.TextBoxFor(x => x.Guitar3.ProductionYear, new { Placeholder = "Production Year" })
                    <div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar3.ProductionYear)</div>
                    <a class="icon delete" data-delete-id="3">Delete</a>
                </div>
            </div>
    

    person Slinky    schedule 03.02.2014    source источник


    Ответы (2)


    В документации указано, что сложные графы должны использовать специализированный валидатор. Вы можете использовать его так:

    public class Customer {
      public string Name { get; set; }
      public Address Address { get; set; }
    }
    
    public class Address {
     public string Line1 { get; set; }
     public string Line2 { get; set; }
     public string Town { get; set; }
     public string County { get; set; }
     public string Postcode { get; set; }
    }
    
    public class AddressValidator : AbstractValidator<Address> {
      public AddressValidator() {
        RuleFor(address => address.Postcode).NotNull();
        //etc
      }
    }
    
    public class CustomerValidator : AbstractValidator<Customer> {
      public CustomerValidator() {
        RuleFor(customer => customer.Name).NotNull();
        RuleFor(customer => customer.Address).SetValidator(new AddressValidator())
      }
    

    }

    Источник: Повторное использование валидаторов для сложных свойств

    http://fluentvalidation.codeplex.com/wikipage?title=CreatingAValidator&referringTitle=Documentation

    Для вашего варианта использования вы должны создать валидатор гитары и валидатор модели для объекта агрегации. Я помню, как мой друг столкнулся с похожими проблемами, потому что валидатор не знает, как пройти по графу объектов без промежуточного валидатора.

    person Patrick Huber    schedule 03.02.2014
    comment
    Патрик, спасибо. Я пробовал это после того, как вы предложили это и те же результаты. - person Slinky; 03.02.2014
    comment
    мвк3 или мвк4? Убедитесь, что вы используете правильную версию для каждой версии MVC. Кроме того, можете ли вы показать вывод из представления, а не содержимое представления? Валидаторы будут создавать стандартную разметку, вы можете увидеть пример между ненавязчивым включением и ненавязчивым выключением здесь: bradwilson.typepad.com/blog/2010/10/. Убедитесь, что вы включили onobtrusive либо в файле web.config, либо в коде. - person Patrick Huber; 04.02.2014
    comment
    @PatrickHuber Можете ли вы объяснить мне, как вы обрабатываете объект Id, если у клиента есть свойство ID. - person Anirudha Gupta; 04.02.2014
    comment
    @PatrickHuber использует Mvc3. Я подтвердил, что установлен правильный пакет FluentValidation, а также предоставил фрагмент сгенерированного HTML, который включен в мой обновленный текст вопроса. - person Slinky; 04.02.2014

    Я понял проблему.

    Класс "Гитара"

    public class Guitar
    {
        public string Model { get; set; }
        public int? ProductionYear { get; set; } 
        public string Make { get; set; }
    }
    

    Требуется декоратор типа Validator

     [Validator(typeof(GuitarValidator))]
    



    Верно

        [Validator(typeof(GuitarValidator))]
        public class Guitar
        {
            public string Model { get; set; }
            public int? ProductionYear { get; set; } 
            public string Make { get; set; }
        }
    
    person Slinky    schedule 04.02.2014
    comment
    Я предпочитаю подход Патрика. Использование атрибутов означает, что проект, содержащий ваши классы, требует зависимости от FluentValidation, а использование SetValidator — нет. Тот же принцип применяется для быстрых конфигураций в EF. - person Matthew Layton; 04.06.2018