I'm using ASP.NET Core 2.2 and I'm using model binding for uploading file.
This is my UserViewModel
public class UserViewModel {     [Required(ErrorMessage = "Please select a file.")]     [DataType(DataType.Upload)]     public IFormFile Photo { get; set; } }   This is MyView
@model UserViewModel  <form method="post"       asp-action="UploadPhoto"       asp-controller="TestFileUpload"       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>   And finally this is MyController
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> UploadPhoto(UserViewModel userViewModel) {     if (ModelState.IsValid)     {         var formFile = userViewModel.Photo;         if (formFile == null || formFile.Length == 0)         {             ModelState.AddModelError("", "Uploaded file is empty or null.");             return View(viewName: "Index");         }          var uploadsRootFolder = Path.Combine(_environment.WebRootPath, "uploads");         if (!Directory.Exists(uploadsRootFolder))         {             Directory.CreateDirectory(uploadsRootFolder);         }          var filePath = Path.Combine(uploadsRootFolder, formFile.FileName);         using (var fileStream = new FileStream(filePath, FileMode.Create))         {             await formFile.CopyToAsync(fileStream).ConfigureAwait(false);         }          RedirectToAction("Index");     }     return View(viewName: "Index"); }   How can I limit uploaded files to lower than 5MB with specific extensions like .jpeg and .png ? I think both of these validations are done in the ViewModel. But I don't know how to do that.
You could custom validation attribute MaxFileSizeAttribute like below
MaxFileSizeAttribute
public class MaxFileSizeAttribute : ValidationAttribute {     private readonly int _maxFileSize;     public MaxFileSizeAttribute(int maxFileSize)     {         _maxFileSize = maxFileSize;     }      protected override ValidationResult IsValid(     object value, ValidationContext validationContext)     {         var file = value as IFormFile;         if (file != null)         {            if (file.Length > _maxFileSize)             {                 return new ValidationResult(GetErrorMessage());             }         }          return ValidationResult.Success;     }      public string GetErrorMessage()     {         return $"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 file = value as IFormFile;         if (file != null)         {             var extension = Path.GetExtension(file.FileName);             if (!_extensions.Contains(extension.ToLower()))             {                 return new ValidationResult(GetErrorMessage());             }         }                  return ValidationResult.Success;     }      public string GetErrorMessage()     {         return $"This photo extension is not allowed!";     } }  Add MaxFileSize attribute and AllowedExtensions attribute to Photo property
public class UserViewModel {         [Required(ErrorMessage = "Please select a file.")]         [DataType(DataType.Upload)]         [MaxFileSize(5* 1024 * 1024)]         [AllowedExtensions(new string[] { ".jpg", ".png" })]         public IFormFile Photo { get; set; }  } 
                        This is how I use the custom validation attributes, almost the same as @xueli-chen 's answer but production-ready.
FileExtensionsAttribute
using System; using System.ComponentModel.DataAnnotations; using System.Globalization; using System.IO; using System.Linq;  using Microsoft.AspNetCore.Http;  using NewsPassWebApi.Properties;  namespace NewsPassWebApi.Models.DataAnnotaions {     /// <summary>     /// Validation attribute to assert an <see cref="IFormFile">IFormFile</see> property, field or parameter has a specific extention.     /// </summary>     [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]     public sealed class FileExtensionsAttribute : ValidationAttribute     {         private string _extensions;          /// <summary>         /// Gets or sets the acceptable extensions of the file.         /// </summary>         public string Extensions         {             get             {                 // Default file extensions match those from jquery validate.                 return string.IsNullOrEmpty(_extensions) ? "png,jpg,jpeg,gif" : _extensions;             }             set             {                 _extensions = value;             }         }          private string ExtensionsNormalized         {             get             {                 return Extensions.Replace(" ", "", StringComparison.Ordinal).ToUpperInvariant();             }         }          /// <summary>         /// Parameterless constructor.         /// </summary>         public FileExtensionsAttribute() : base(() => Resources.FileExtensionsAttribute_ValidationError)         { }          /// <summary>         /// Override of <see cref="ValidationAttribute.IsValid(object)"/>         /// </summary>         /// <remarks>         /// This method returns <c>true</c> if the <paramref name="value"/> is null.           /// It is assumed the <see cref="RequiredAttribute"/> is used if the value may not be null.         /// </remarks>         /// <param name="value">The value to test.</param>         /// <returns><c>true</c> if the value is null or it's extension is not invluded in the set extensionss</returns>         public override bool IsValid(object value)         {             // Automatically pass if value is null. RequiredAttribute should be used to assert a value is not null.             if (value == null)             {                 return true;             }              // We expect a cast exception if the passed value was not an IFormFile.             return ExtensionsNormalized.Split(",").Contains(Path.GetExtension(((IFormFile)value).FileName).ToUpperInvariant());         }          /// <summary>         /// Override of <see cref="ValidationAttribute.FormatErrorMessage"/>         /// </summary>         /// <param name="name">The name to include in the formatted string</param>         /// <returns>A localized string to describe the acceptable extensions</returns>         public override string FormatErrorMessage(string name)         {             return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, Extensions);         }     } }   FileSizeAttribute
using System; using System.ComponentModel.DataAnnotations; using System.Globalization;  using Microsoft.AspNetCore.Http;  using NewsPassWebApi.Properties;  namespace NewsPassWebApi.Models.DataAnnotaions {     /// <summary>     /// Validation attribute to assert an <see cref="IFormFile">IFormFile</see> property, field or parameter does not exceed a maximum size.     /// </summary>     [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]     public sealed class FileSizeAttribute : ValidationAttribute     {         /// <summary>         /// Gets the maximum acceptable size of the file.         /// </summary>         public long MaximumSize { get; private set; }          /// <summary>         /// Gets or sets the minimum acceptable size of the file.         /// </summary>         public int MinimumSize { get; set; }          /// <summary>         /// Constructor that accepts the maximum size of the file.         /// </summary>         /// <param name="maximumSize">The maximum size, inclusive.  It may not be negative.</param>         public FileSizeAttribute(int maximumSize) : base(() => Resources.FileSizeAttribute_ValidationError)         {             MaximumSize = maximumSize;         }          /// <summary>         /// Override of <see cref="ValidationAttribute.IsValid(object)"/>         /// </summary>         /// <remarks>         /// This method returns <c>true</c> if the <paramref name="value"/> is null.           /// It is assumed the <see cref="RequiredAttribute"/> is used if the value may not be null.         /// </remarks>         /// <param name="value">The value to test.</param>         /// <returns><c>true</c> if the value is null or it's size is less than or equal to the set maximum size</returns>         /// <exception cref="InvalidOperationException"> is thrown if the current attribute is ill-formed.</exception>         public override bool IsValid(object value)         {             // Check the lengths for legality             EnsureLegalSizes();              // Automatically pass if value is null. RequiredAttribute should be used to assert a value is not null.             // We expect a cast exception if the passed value was not an IFormFile.             var length = value == null ? 0 : ((IFormFile)value).Length;              return value == null || (length >= MinimumSize && length <= MaximumSize);         }          /// <summary>         /// Override of <see cref="ValidationAttribute.FormatErrorMessage"/>         /// </summary>         /// <param name="name">The name to include in the formatted string</param>         /// <returns>A localized string to describe the maximum acceptable size</returns>         /// <exception cref="InvalidOperationException"> is thrown if the current attribute is ill-formed.</exception>         public override string FormatErrorMessage(string name)         {             EnsureLegalSizes();              string errorMessage = MinimumSize != 0 ? Resources.FileSizeAttribute_ValidationErrorIncludingMinimum : ErrorMessageString;              // it's ok to pass in the minLength even for the error message without a {2} param since String.Format will just ignore extra arguments             return string.Format(CultureInfo.CurrentCulture, errorMessage, name, MaximumSize, MinimumSize);         }          /// <summary>         /// Checks that MinimumSize and MaximumSize have legal values.  Throws InvalidOperationException if not.         /// </summary>         private void EnsureLegalSizes()         {             if (MaximumSize < 0)             {                 throw new InvalidOperationException(Resources.FileSizeAttribute_InvalidMaxSize);             }              if (MaximumSize < MinimumSize)             {                 throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resources.RangeAttribute_MinGreaterThanMax, MaximumSize, MinimumSize));             }         }     } }   now you can use those like any built-in validation attribute including custom/localized error messages, max-min file sizes, and file extensions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With