Estoy usando ASP.NET Core 2.2 y estoy usando el enlace de modelo para cargar el archivo.
Este es mi UserViewModel
public class UserViewModel { [Required(ErrorMessage = "Please select a file.")] [DataType(DataType.Upload)] public IFormFile Photo { get; set; } }Esta es mi vista
@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>Y finalmente esto es 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"); }¿Cómo puedo limitar los archivos cargados a menos de 5 MB con extensiones específicas como .jpeg y .png? Creo que ambas validaciones se realizan en ViewModel. Pero no sé cómo hacer eso.
Podría personalizar el atributo de validación MaxFileSizeAttribute como se muestra a continuación
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."; } }Atributo de extensiones permitidas
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!"; } } Agregue el atributo MaxFileSize y el atributo AllowedExtensions a la propiedad Photo
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; } }Puede implementar IValidatableObject para validar su modelo.
public class UserViewModel : IValidatableObject { [Required(ErrorMessage = "Please select a file.")] [DataType(DataType.Upload)] public IFormFile Photo { get; set; } public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { var photo = ((UserViewModel)validationContext.ObjectInstance).Photo; var extension = Path.GetExtension(photo.FileName); var size = photo.Length; if (!extension.ToLower().Equals(".jpg")) yield return new ValidationResult("File extension is not valid."); if(size > (5 * 1024 * 1024)) yield return new ValidationResult("File size is bigger than 5MB."); } }Siguiendo el comentario anterior , puede agregar esta clase:
public class ValidateModelStateFilter : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext context) { if (context.ModelState.IsValid) { return; } var validationErrors = context.ModelState .Keys .SelectMany(k => context.ModelState[k].Errors) .Select(e => e.ErrorMessage) .ToArray(); var json = new JsonErrorResponse { Messages = validationErrors }; context.Result = new BadRequestObjectResult(json); } }Finalmente, agregue el filtro a los controladores en la clase de inicio:
services.AddControllers(options => { options.Filters.Add(typeof(ValidateModelStateFilter)); })