1
votes

I have a complex class structure as below.

public class Account
{ 
   public List<Name> Person {get;set;}
   public List<Address> Address {get;set;}
   public string Email   {get;set;}
   public string ConfirmEmail {get;set;}
}

public class Name 
{
  public string FirstName {get; set;}
  public string LastName {get;set;}
  public string DateOfBirth {get;set;}
  public string SSN {get;Set;}
}

public class Address 
{
  public string AddressLine1 {get;set;}
  public string AddressLine2 {get;set;}
  public string City {get;set;}
  public string State {get;set;}
}

Here are the Validators

public class AccountValidator : AbstractValidator<Account>
{
  public AccountValidator()
  {
    RuleSet("Account", () =>
    { 
     RuleFor(account => account.Person).SetCollectionValidator(new NameValidator());
     RuleFor(account => account.Address).SetCollectionValidator(new AddressValidator());
   });
     }
   }
  }


public class NameValidator : AbstractValidator<Name>
 {
    public NameValidator()
     {
        RuleSet("Account", () =>
        {
            SharedRules();
        });

        RuleSet("Name_DateOfBirth", () =>
        {
          SharedRules();
          RuleFor(name => name.DateOfBirth).NotEmpty());
        });
    }

     void SharedRules()
    {
      RuleFor(name => name.FirstName).NotEmpty());
      RuleFor(name => name.FirstName).Length(1, 20));
      RuleFor(name => name.LastName).NotEmpty());
      RuleFor(name => name.LastName).Length(1, 20));
      }
 }
public class AddressValidator : AbstractValidator<Address>
{
  public AddressValidator()
  {
    RuleSet("Account", () =>
    {
      SharedRules();
     });
  }

    void SharedRules()
    {

        RuleFor(address => address.AddressLine1).NotEmpty());
        ... 
        .... etc..
    }
 }

I have [HttpPost] ActionMethod as below :-

[HttpPost]
public ActionResult Register([CustomizeValidator(RuleSet="Account")] Account model)
 {
    if(MoelState.IsValid)
    {
        //blah blah
    }
    else 
    {
      //blah blah
    }
 }

I have view For Register as follows :-

@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "Register" }))
{
   @Html.AntiForgeryToken();   
   <h1>Register</h1>    
   @Html.ValidationSummary(false)
   <div id="divName">   
     @Html.EditorFor(m => m.Person[0])
   </div>
      for (int i = 0; i < 2; i++)
     {
        if (i == 0)
       {  
        <div id="divHomeAdd">
            @Html.EditorFor(m => m.Address[0])
        </div>       
       <input type="checkbox"/>   
       <label for="nohomeaddress"> Do not Have Home Address </label>
       }
        if (i == 1)
      { 
        <div id="divMailingAdd">
            @Html.EditorFor(m => m.Address[1])
        </div>
        }
      }

    @Html.TextBoxCustomFor(m => m.Email)   
    @Html.TextBoxCustomFor(m => m.ConfirmEmail) 
    <input type="submit" value="Register" id="btnRegister" name="Register" />
 }

I have to display EditorFor() Name , but only FirstName and LastName is required i.e. need to fire RuelSet for "Account" in NameValidator.

For some Other View I need to fire "Name_DateOfBirth" RuleSet becausethat screen needs Date of Birth as required field along with normal First Name and Last Name. How to do that in MVC ?

I have to display Validation for Home Address if checkbox for "No Home Address" is checked then only need to validate the Mailing Address property.

How can i make use of RuleSets in such scenario ? Do we need to have same Rule Name in Parent and Child ? i.e. "Account" Rule should exist both in AccountValidator as well as NameValidator so that it fires ?

1

1 Answers

1
votes

What you have so far looks like a good start. Using the view name as the ruleset name is a good idea as you will have a good relationship between which fields are on the view, and which ones get validated.

The only thing I noticed is you are missing the ValidatorAttribute decorations on your model classes.

Here is some good documentation if you haven't seen it already.