title: ASP.NET MVC custom multiple fields validation
body: <p>I'm developing an ASP.NET MVC 5.2.3 custom data annotation for validation in Visual Studio 2015. It needs to take any number of fields and ensure that if one has a value, they all must have a value; if they're all null/blank, it should be okay. </p>
  
  <p>A few examples have helped:</p>
  
  <ul>
  <li><a href="https://stackoverflow.com/questions/8284207/asp-net-mvc-implement-custom-validator-use-iclientvalidatable">ASP.NET MVC implement custom validator use IClientValidatable</a></li>
  <li><a href="https://stackoverflow.com/questions/6075339/mvc-form-validation-on-multiple-fields">MVC Form Validation on Multiple Fields</a></li>
  <li><a href="http://www.macaalay.com/2014/02/24/unobtrusive-client-and-server-side-age-validation-in-mvc-using-custom-data-annotations/" rel="nofollow noreferrer">http://www.macaalay.com/2014/02/24/unobtrusive-client-and-server-side-age-validation-in-mvc-using-custom-data-annotations/</a></li>
  </ul>
  
  <p>However, I'm not sure how to do the client-side validation where you have an unknown number of fields being validated. </p>
  
  <p>How do you pass that to the client using the implementation of the <code>GetClientValidationRules()</code> method of the <code>IClientValidatable</code> interface?</p>
  
  <p>Also, how do I apply this new data annotation to the properties on my view model? Would it look like this?</p>
  
  <pre><code>[MultipleRequired("AppNumber", "UserId", /* more fields */), ErrorMessage = "Something..."]
  [DisplayName("App #")]
  public int AppNumber { get; set; }
  
  [DisplayName("User ID")]
  public int UserId { get; set; }
  </code></pre>
  
  <p>Here's as far as I could get with the <code>MultipleRequiredAttribute</code> custom data annotation class:</p>
  
  <pre><code>public class MultipleRequiredAttribute : ValidationAttribute, IClientValidatable
  {
      private readonly string[] _fields;
      public MultipleRequiredAttribute(params string[] fields)
      {
          _fields = fields;
      }
  
      protected override ValidationResult IsValid(object value, ValidationContext validationContext)
      {
          // If any field has value, then all must have value
          var anyHasValue = _fields.Any(f =&gt; !string.IsNullOrEmpty(f));
  
          if (!anyHasValue) return null;
  
          foreach (var field in _fields)
          {
              var property = validationContext.ObjectType.GetProperty(field);
              if (property == null)
                  return new ValidationResult($"Property '{field}' is undefined.");
  
              var fieldValue = property.GetValue(validationContext.ObjectInstance, null);
  
              if (string.IsNullOrEmpty(fieldValue?.ToString()))
                  return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
          }
  
          return null;
      }
  
      public IEnumerable&lt;ModelClientValidationRule&gt; GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
      {
          yield return new ModelClientValidationRule
          {
              ErrorMessage = ErrorMessage,
              ValidationType = "multiplerequired"
          };
      }
  }
  </code></pre>
  
  <p>Thank you.</p>