title: MVC3 Custom Unobtrusive Validator on a List of Objects
body: <p>The basic question to start: How can you put a custom, unobtrusive validator ontop of a list of objects within your model? Like, say my model allows multiple file uploads, and thus I have a list of files, and I want my validator to run on each of those files?</p>
  
  <p>Now for a specific example. I've got a custom, unobtrusive validator that checks to see if a file extension is not within a list of prohibited extensions: </p>
  
  <pre><code>public class FileExtensionValidatorAttribute : ValidationAttribute, IClientValidatable {
  
      protected static string[] PROHIBITED_EXTENSIONS = {
          // ... List of extensions I don't allow.
      };
  
      public override bool IsValid(object value) {
          if (value is IEnumerable&lt;HttpPostedFileBase&gt;) {
              foreach (var file in (IEnumerable&lt;HttpPostedFileBase&gt;)value) {
                  var fileName = file.FileName;
                  if (PROHIBITED_EXTENSIONS.Any(x =&gt; fileName.EndsWith(x))) return false;
              }
          } else {
              var file = (HttpPostedFileBase)value;
              var fileName = file.FileName;
              if (PROHIBITED_EXTENSIONS.Any(x =&gt; fileName.EndsWith(x))) return false;
          }
  
          return true;
      }
  
      public IEnumerable&lt;ModelClientValidationRule&gt; GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
          var modelClientVlidationRule = new ModelClientValidationRule {
              ErrorMessage = this.ErrorMessageString,
              ValidationType = "fileextension",
          };
          modelClientVlidationRule.ValidationParameters.Add("prohibitedextensions", string.Join("|", PROHIBITED_EXTENSIONS));
  
          yield return modelClientVlidationRule;
      }
  }
  </code></pre>
  
  <p>Take note in my IsValid that I built this to accept a single file or a list of files.</p>
  
  <p>In my model class, I can make use of this on a single HttpPostedFileBase:</p>
  
  <pre><code>[FileExtensionValidator(ErrorMessage = "Invalid Extension")]
  public HttpPostedFileBase Upload { get; set; }
  </code></pre>
  
  <p>Then I attach to jquery's validator in my view:</p>
  
  <pre><code>jQuery.validator.addMethod("fileExtension", function (value, element, param) {
      var extension = "";
      var dotIndex = value.lastIndexOf('.');
      if (dotIndex != -1) extension = value.substring(dotIndex + 1).toLowerCase();
  
      return $.inArray(extension, param.prohibitedExtensions) === -1;
  });
  
  jQuery.validator.unobtrusive.adapters.add('fileextension', ['prohibitedextensions'], function (options) {
      options.rules['fileExtension'] = {
          prohibitedExtensions: options.params.prohibitedextensions.split('|')
      };
      options.messages['fileExtension'] = options.message;
  });
  </code></pre>
  
  <p>This all works great, client side and server side ...but only on a single HttpPostedFileBase. The problem is that I need to provide users the ability to upload one or more files. If I change my model to this:</p>
  
  <pre><code>[FileExtensionValidator(ErrorMessage = "Invalid Extension")]
  public List&lt;HttpPostedFileBase&gt; Uploads { get; set; }
  </code></pre>
  
  <p>...the Client-side validation no longer runs; only the server-side works. This is evident when doing a view-source. The &lt;input&gt; tag that gets generated is missing all the data-val attributes it needs to run. In doing a debug, GetClientValidationRules is never called.</p>
  
  <p>What am I missing?</p>
  
  <p>Could this be because of how I render it? I'm simply using an EditorTemplate for HttpPostedFileBase:</p>
  
  <pre><code>@model System.Web.HttpPostedFileBase
  @Html.TextBoxFor(m =&gt; m, new { type = "file", size = 60 })
  </code></pre>
  
  <p>...and my view renders it like this:</p>
  
  <pre><code>&lt;p&gt;@Html.EditorFor(m =&gt; m.Uploads)&lt;/p&gt;
  </code></pre>
  
  <p>Any advice is appreciated.</p>