Asp.net-Mvc-4

如何在 Asp.Net MVC 4 中驗證 HttpPostedFileBase 屬性的文件類型?

  • February 15, 2021

我正在嘗試驗證文件類型的HttpPostedFileBase屬性以檢查文件類型,但我不能這樣做,因為驗證正在通過。我怎麼能這樣做?

模型

public class EmpresaModel{

[Required(ErrorMessage="Choose a file .JPG, .JPEG or .PNG file")]
[ValidateFile(ErrorMessage = "Please select a .JPG, .JPEG or .PNG file")]
public HttpPostedFileBase imagem { get; set; }

}

HTML

<div class="form-group">
     <label for="@Html.IdFor(model => model.imagem)" class="cols-sm-2 control-label">Escolha a imagem <img src="~/Imagens/required.png" height="6" width="6"></label>
      @Html.TextBoxFor(model => Model.imagem, new { Class = "form-control", placeholder = "Informe a imagem", type = "file" })
      @Html.ValidationMessageFor(model => Model.imagem)
</div>

驗證文件屬性

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Web;

//validate file if a valid image
public class ValidateFileAttribute : RequiredAttribute{

   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<ImageFormat> formats = getValidFormats();

       foreach (ImageFormat format in formats)
       {
           if(rawFormat.Equals(format))
           {
               return true;
           }
       }
       return false;
   }

   private List<ImageFormat> getValidFormats()
   {
       List<ImageFormat> formats = new List<ImageFormat>();
       formats.Add(ImageFormat.Png);
       formats.Add(ImageFormat.Jpeg);        
       //add types here
       return formats;
   }


}

由於您的屬性繼承自現有屬性,因此需要在其中註冊global.asax(請參閱此答案以獲取範例),但是在您的情況下要這樣做。您的驗證程式碼不起作用,並且文件類型屬性不應繼承自RequiredAttribute- 它需要繼承自ValidationAttribute,如果您想要客戶端驗證,那麼它還需要實現IClientValidatable. 驗證文件類型的屬性將是(請注意此程式碼,如果用於IEnumerable<HttpPostedFileBase>驗證集合中每個文件的屬性)

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class FileTypeAttribute : ValidationAttribute, IClientValidatable
{
   private const string _DefaultErrorMessage = "Only the following file types are allowed: {0}";
   private IEnumerable<string> _ValidTypes { get; set; }

   public FileTypeAttribute(string validTypes)
   {
       _ValidTypes = validTypes.Split(',').Select(s => s.Trim().ToLower());
       ErrorMessage = string.Format(_DefaultErrorMessage, string.Join(" or ", _ValidTypes));
   }

   protected override ValidationResult IsValid(object value, ValidationContext validationContext)
   {
       IEnumerable<HttpPostedFileBase> files = value as IEnumerable<HttpPostedFileBase>;
       if (files != null)
       {
           foreach(HttpPostedFileBase file in files)
           {
               if (file != null && !_ValidTypes.Any(e => file.FileName.EndsWith(e)))
               {
                   return new ValidationResult(ErrorMessageString);
               }
           }
       }
       return ValidationResult.Success;
   }

   public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
   {
       var rule = new ModelClientValidationRule
       {
           ValidationType = "filetype",
           ErrorMessage = ErrorMessageString
       };
       rule.ValidationParameters.Add("validtypes", string.Join(",", _ValidTypes));
       yield return rule;
   }
}

它將應用於屬性

[FileType("JPG,JPEG,PNG")]
public IEnumerable<HttpPostedFileBase> Attachments { get; set; }

並且在視圖中

@Html.TextBoxFor(m => m.Attachments, new { type = "file", multiple = "multiple" })
@Html.ValidationMessageFor(m => m.Attachments)

然後,客戶端驗證需要以下腳本(與jquery.validate.jsjquery.validate.unobtrusive.js

$.validator.unobtrusive.adapters.add('filetype', ['validtypes'], function (options) {
   options.rules['filetype'] = { validtypes: options.params.validtypes.split(',') };
   options.messages['filetype'] = options.message;
});

$.validator.addMethod("filetype", function (value, element, param) {
   for (var i = 0; i < element.files.length; i++) {
       var extension = getFileExtension(element.files[i].name);
       if ($.inArray(extension, param.validtypes) === -1) {
           return false;
       }
   }
   return true;
});

function getFileExtension(fileName) {
   if (/[.]/.exec(fileName)) {
       return /[^.]+$/.exec(fileName)[0].toLowerCase();
   }
   return null;
}

請注意,您的程式碼還試圖驗證文件的最大大小,這需要是一個單獨的驗證屬性。有關驗證最大允許大小的驗證屬性範例,請參閱本文

此外,我推薦ASP.NET MVC 3 中的驗證完整指南 - 第 2 部分作為創建自定義驗證屬性的良好指南

請注意 EndsWith 預設情況下區分大小寫。所以我會改變這個:

if (file != null && !_ValidTypes.Any(e => file.FileName.EndsWith(e)))

對此

if (file != null && !_ValidTypes.Any(e => file.FileName.EndsWith(e, StringComparison.OrdinalIgnoreCase)))

引用自:https://stackoverflow.com/questions/40199870