Comment valider le fichier téléchargé dans ASP.NET MVC?

J’ai une action Create qui prend un object entité et une image HttpPostedFileBase. L’image n’appartient pas au modèle d’entité.

Je peux enregistrer l’object entité dans la firebase database et le fichier sur le disque, mais je ne suis pas sûr de savoir comment valider ces règles métier:

  • L’image est requirejse
  • Le type de contenu doit être “image / png”
  • Ne doit pas dépasser 1 Mo

Un atsortingbut de validation personnalisé est une solution:

public class ValidateFileAtsortingbute : RequiredAtsortingbute { public override bool IsValid(object value) { var file = value as HttpPostedFileBase; if (file == null) { return false; } if (file.ContentLength > 1 * 1024 * 1024) { return false; } try { using (var img = Image.FromStream(file.InputStream)) { return img.RawFormat.Equals(ImageFormat.Png); } } catch { } return false; } } 

et ensuite appliquer sur votre modèle:

 public class MyViewModel { [ValidateFile(ErrorMessage = "Please select a PNG image smaller than 1MB")] public HttpPostedFileBase File { get; set; } } 

Le contrôleur pourrait ressembler à ceci:

 public class HomeController : Controller { public ActionResult Index() { var model = new MyViewModel(); return View(model); } [HttpPost] public ActionResult Index(MyViewModel model) { if (!ModelState.IsValid) { return View(model); } // The uploaded image corresponds to our business rules => process it var fileName = Path.GetFileName(model.File.FileName); var path = Path.Combine(Server.MapPath("~/App_Data"), fileName); model.File.SaveAs(path); return Content("Thanks for uploading", "text/plain"); } } 

et la vue:

 @model MyViewModel @using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" })) { @Html.LabelFor(x => x.File)  @Html.ValidationMessageFor(x => x.File)  } 

Sur la base de la réponse de Darin Dimitrov que j’ai trouvée très utile, j’ai une version adaptée qui permet de vérifier plusieurs types de fichiers, ce que je cherchais initialement.

 public override bool IsValid(object value) { bool isValid = false; var file = value as HttpPostedFileBase; if (file == null || file.ContentLength > 1 * 1024 * 1024) { return isValid; } if (IsFileTypeValid(file)) { isValid = true; } return isValid; } private bool IsFileTypeValid(HttpPostedFileBase file) { bool isValid = false; try { using (var img = Image.FromStream(file.InputStream)) { if (IsOneOfValidFormats(img.RawFormat)) { isValid = true; } } } catch { //Image is invalid } return isValid; } private bool IsOneOfValidFormats(ImageFormat rawFormat) { List formats = getValidFormats(); foreach (ImageFormat format in formats) { if(rawFormat.Equals(format)) { return true; } } return false; } private List getValidFormats() { List formats = new List(); formats.Add(ImageFormat.Png); formats.Add(ImageFormat.Jpeg); formats.Add(ImageFormat.Gif); //add types here return formats; } } 

Voici un moyen de le faire en utilisant viewmodel, jetez un oeil sur le code entier ici

Asp.Net MVC validation de la taille pour la taille et le type Créer un modèle de vue comme indiqué ci-dessous avec FileSize et FileTypes

 public class ValidateFiles { [FileSize(10240)] [FileTypes("doc,docx,xlsx")] public HttpPostedFileBase File { get; set; } } 

Créer des atsortingbuts personnalisés

 public class FileSizeAtsortingbute : ValidationAtsortingbute { private readonly int _maxSize; public FileSizeAtsortingbute(int maxSize) { _maxSize = maxSize; } //..... //..... } public class FileTypesAtsortingbute : ValidationAtsortingbute { private readonly List _types; public FileTypesAtsortingbute(ssortingng types) { _types = types.Split(',').ToList(); } //.... //... } 

Vous pouvez envisager d’enregistrer l’image dans la firebase database également:

  using (MemoryStream mstream = new MemoryStream()) { if (context.Request.Browser.Browser == "IE") context.Request.Files[0].InputStream.CopyTo(mstream); else context.Request.InputStream.CopyTo(mstream); if (ValidateIcon(mstream)) { Icon icon = new Icon() { ImageData = mstream.ToArray(), MimeType = context.Request.ContentType }; this.iconRepository.SaveOrUpdate(icon); } } 

Je l’utilise avec NHibernate – entité définie:

  public Icon(int id, byte[] imageData, ssortingng mimeType) { this.Id = id; this.ImageData = imageData; this.MimeType = mimeType; } public virtual byte[] ImageData { get; set; } public virtual ssortingng MimeType { get; set; } 

Ensuite, vous pouvez retourner l’image en tant que FileContentResult:

  public FileContentResult GetIcon(int? iconId) { try { if (!iconId.HasValue) return null; Icon icon = this.iconRepository.Get(iconId.Value); return File(icon.ImageData, icon.MimeType); } catch (Exception ex) { Log.ErrorFormat("ImageController: GetIcon Critical Error: {0}", ex); return null; } } 

Notez que ceci utilise ajax submit. Plus facile d’accéder au stream de données autrement.