【问题标题】:Unobtrusively Validating Complex View Models with Fluent Validation - MVC3使用 Fluent Validation 不显眼地验证复杂的视图模型 - MVC3
【发布时间】:2014-02-03 16:33:21
【问题描述】:

我试图弄清楚为什么我的FluentValidation 没有不显眼地验证我的某些视图模型属性。

我通过 NuGet 安装了 MVC3 的 FluentValidation 包:

  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 对象的其他 2 个属性没有。

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

我阅读了 FluentValidation 文档,现在特别关注 limitations regarding FluentValidation's client-side validation of lists,但这不是一个列表,所以我希望有人能看到问题所在和/或提供一些建议。

我也尝试使用自定义 Guitar 对象验证器,但仍然得到相同的结果

观察

  • 正在生成客户端验证并触发属性 FirstName、LasteName、Phone 和 Email

  • 我确实注意到,当用户未填写这些对象时,ModelState 对这些对象无效,但我不知道为什么没有生成客户端验证并随后触发。

  • 为 Guitar 对象生成的 HTML 表单缺少不显眼的验证属性。 FirstName、LastName、Email 和 Phone 等其他属性验证正常
  • 示例

        <!-- 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>
    

    【问题讨论】:

      标签: c# asp.net-mvc-3 fluentvalidation


      【解决方案1】:

      文档指出复杂图形应使用专门的验证器。你可以这样使用它:

      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

      对于您的用例,您将为聚合对象创建一个吉他验证器和一个模型验证器。我记得有一个朋友遇到过类似的问题,因为验证器不知道如何在没有中间验证器的情况下遍历对象图。

      【讨论】:

      • 帕特里克,谢谢。在您提出建议并获得相同结果之后,我确实尝试过。
      • Mvc3 还是 Mvc4?确保每个 MVC 版本都使用正确的版本。另外,您可以显示视图的输出而不是视图内容吗?验证器将生成标准标记,您可以在此处查看不显眼的开启与不显眼的关闭之间的示例:bradwilson.typepad.com/blog/2010/10/…。确保在 web.config 中或通过代码打开 onobtrusive。
      • @PatrickHuber 你能解释一下如果客户有 ID 属性,你如何处理 Id 对象吗?
      • @PatrickHuber 使用 Mvc3。我确认安装了正确的 FluentValidation 包,并提供了生成的 HTML 的 sn-p,它包含在我更新的问题文本中。
      【解决方案2】:

      我发现了问题。

      吉他课

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

      需要一个验证器类型的装饰器

       [Validator(typeof(GuitarValidator))]
      



      正确

          [Validator(typeof(GuitarValidator))]
          public class Guitar
          {
              public string Model { get; set; }
              public int? ProductionYear { get; set; } 
              public string Make { get; set; }
          }
      

      【讨论】:

      • 我更喜欢帕特里克的方法。使用属性意味着包含您的类的项目需要对 FluentValidation 的依赖,而使用 SetValidator 则不需要。同样的原则也适用于 EF 中的流畅配置。
      猜你喜欢
      • 2012-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-06
      • 2011-07-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多