如何在Asp.Net MVC 4中验证HttpPostedFileBase属性的文件类型?

时间:2016-10-23 05:29:46

标签: asp.net-mvc-4

我正在尝试验证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>

ValidateFileAttribute

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


}

2 个答案:

答案 0 :(得分:15)

由于您的属性继承自现有属性,因此需要在global.asax中注册(例如,请参阅this answer),但在您的案件。您的验证代码不起作用,文件类型属性不应继承自RequiredAttribute - 它需要从ValidationAttribute继承,如果您想要客户端验证,那么它还需要实现{{1} }}。验证文件类型的属性是(如果属性为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.js

结合使用
jquery.validate.unobtrusive.js

请注意,您的代码还尝试验证文件的最大大小,该大小需要是单独的验证属性。有关验证最大允许大小的验证属性的示例,请参阅this article

此外,我建议The Complete Guide To Validation In ASP.NET MVC 3 - Part 2作为创建自定义验证属性的良好指南

答案 1 :(得分:0)

请注意,EndsWith默认情况下区分大小写。所以我要改变这个:

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

对此

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