Since your attribute inherits from and the existing attribute, it will need to be registered in global.asax (see this answer for an example), however do not do this in your case. Your verification code does not work, and the file type attribute should not inherit from RequiredAttribute - it needs to inherit from ValidationAttribute , and if you want to check on the client side, then you also need to implement IClientValidatable . The attribute for checking file types will be (pay attention to this code if for a property that is IEnumerable<HttpPostedFileBase> and checks each file in the collection)
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public class FileTypeAttribute : ValidationAttribute, IClientValidatable { private const string _DefaultErrorMessage = "Only the following file types are allowed: {0}"; private IEnumerable<string> _ValidTypes { get; set; } public FileTypeAttribute(string validTypes) { _ValidTypes = validTypes.Split(',').Select(s => s.Trim().ToLower()); ErrorMessage = string.Format(_DefaultErrorMessage, string.Join(" or ", _ValidTypes)); } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { IEnumerable<HttpPostedFileBase> files = value as IEnumerable<HttpPostedFileBase>; if (files != null) { foreach(HttpPostedFileBase file in files) { if (file != null && !_ValidTypes.Any(e => file.FileName.EndsWith(e))) { return new ValidationResult(ErrorMessageString); } } } return ValidationResult.Success; } public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { var rule = new ModelClientValidationRule { ValidationType = "filetype", ErrorMessage = ErrorMessageString }; rule.ValidationParameters.Add("validtypes", string.Join(",", _ValidTypes)); yield return rule; } }
It will be applied to the property as
[FileType("JPG,JPEG,PNG")] public IEnumerable<HttpPostedFileBase> Attachments { get; set; }
and in the presentation
@Html.TextBoxFor(m => m.Attachments, new { type = "file", multiple = "multiple" }) @Html.ValidationMessageFor(m => m.Attachments)
Then, client-side validation requires the following scripts (combined with jquery.validate.js and jquery.validate.unobtrusive.js
$.validator.unobtrusive.adapters.add('filetype', ['validtypes'], function (options) { options.rules['filetype'] = { validtypes: options.params.validtypes.split(',') }; options.messages['filetype'] = options.message; }); $.validator.addMethod("filetype", function (value, element, param) { for (var i = 0; i < element.files.length; i++) { var extension = getFileExtension(element.files[i].name); if ($.inArray(extension, param.validtypes) === -1) { return false; } } return true; }); function getFileExtension(fileName) { if (/[.]/.exec(fileName)) { return /[^.]+$/.exec(fileName)[0].toLowerCase(); } return null; }
Please note that your code also tries to check the maximum file size, which should be a separate verification attribute. For an example of a validation attribute that validates the maximum size, see this article .
In addition, I recommend the ASP.NET MVC 3 Complete Validation Guide - Part 2 as a Good Guide to Creating Custom Validation Attributes