Search code examples
c#asp.netasp.net-coreef-core-2.1

How to validate uploaded file in ASP.Net Core


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.


Solution

  • 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; }
     }