Search code examples
c#asp.netasp.net-mvcasp.net-core

How to validate uploaded files in ASP.Net MVC


I have a good answer here to validate file extension & file size for just 1 single file.

But how can I validate file extension & file size for "List<IFormFile> ImagesFile"?


Solution

  • The first way is using IValidatableObject:

    public class UserViewModel : IValidatableObject
    {
        public IList<IFormFile> Photo { get; set; }
    
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            var photos = ((UserViewModel)validationContext.ObjectInstance).Photo;
            foreach(var photo in photos)
            {
                var extension = Path.GetExtension(photo.FileName);
                var size = photo.Length;
    
                if (!extension.ToLower().Equals(".jpg")||! extension.ToLower().Equals(".png"))
                    yield return new ValidationResult($"{photo.FileName}'s file extension is not valid.");
    
                if (size > (5 * 1024 * 1024))
                    yield return new ValidationResult($"{photo.FileName}'s file size is bigger than 5MB.");
            }
            
        }
    }
    

    The second way is to custom validation attribute:

    MaxFileSizeAttribute:

    public class MaxFileSizeAttribute : ValidationAttribute
    {
        private readonly int _maxFileSize;
        public MaxFileSizeAttribute(int maxFileSize)
        {
            _maxFileSize = maxFileSize;
        }
    
        protected override ValidationResult IsValid(
        object value, ValidationContext validationContext)
        {
            var files = value as IList<IFormFile>;
            foreach(var file in files)
            {
                if (file != null)
                {
                    if (file.Length > _maxFileSize)
                    {
                        return new ValidationResult(GetErrorMessage(file.FileName));
                    }
                }
            }    
            
    
            return ValidationResult.Success;
        }
    
        public string GetErrorMessage(string name)
        {
            return $"{name}'s size is out of range.Maximum allowed file size is { _maxFileSize} bytes.";
        }
    }
    

    AllowedExtensionsAttribute:

    public class AllowedExtensionsAttribute : ValidationAttribute
    {
        private readonly string[] _extensions;
        public AllowedExtensionsAttribute(string[] extensions)
        {
            _extensions = extensions;
        }
    
        protected override ValidationResult IsValid(
        object value, ValidationContext validationContext)
        {
            var files = value as IList<IFormFile>;
            foreach(var file in files)
            {
                var extension = Path.GetExtension(file.FileName);
                if (file != null)
                {
                    if (!_extensions.Contains(extension.ToLower()))
                    {
                        return new ValidationResult(GetErrorMessage(file.FileName));
                    }
                }
            }
            
            return ValidationResult.Success;
        }
    
        public string GetErrorMessage(string name)
        {
            return $"{name} extension is not allowed!";
        }
    }
    

    Model:

    public class UserViewModel
    {
        [MaxFileSize(5 * 1024 * 1024)]
        [AllowedExtensions(new string[] { ".jpg",".png"})]
        public IList<IFormFile> Photo { get; set; }
    }
    

    View(Upload.cshtml):

    @model UserViewModel
    
    <form method="post"
            asp-action="Upload"
            asp-controller="Home"
            enctype="multipart/form-data">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    
        <input asp-for="Photo" />
        <span asp-validation-for="Photo" class="text-danger"></span>
        <input type="submit" value="Upload" />
    </form>
    

    Controller:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Upload(UserViewModel userViewModel)
    {
        if (!ModelState.IsValid)
        {                
            return View("Upload");
        }
        return View("Index");
    }