Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to validate uploaded file in ASP.NET MVC?

People also ask

How do I validate a file type in C#?

bool CheckFileType(string fileName) { string ext = Path. GetExtension(fileName); switch (ext. ToLower()) { case ". gif": return true; case ".

How can I get file extension in MVC?

string extension = Path. GetExtension(upload. FileName);

What is HttpPostedFileBase?

The HttpPostedFileBase class is an abstract class that contains the same members as the HttpPostedFile class. The HttpPostedFileBase class lets you create derived classes that are like the HttpPostedFile class, but that you can customize and that work outside the ASP.NET pipeline.


A custom validation attribute is one way to go:

public class ValidateFileAttribute : RequiredAttribute
{
    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;
    }
}

and then apply on your model:

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

The controller might look like this:

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

and the view:

@model MyViewModel

@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.LabelFor(x => x.File)
    <input type="file" name="@Html.NameFor(x => x.File)" id="@Html.IdFor(x => x.File)" />
    @Html.ValidationMessageFor(x => x.File)
    <input type="submit" value="upload" />
}

Based on Darin Dimitrov's answer which I have found very helpful, I have an adapted version which allows checks for multiple file types, which is what I was initially looking for.

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);
        formats.Add(ImageFormat.Gif);
        //add types here
        return formats;
    }
}

Here is a way to do it using viewmodel, take a look at whole code here

Asp.Net MVC file validation for size and type Create a viewmodel as shown below with FileSize and FileTypes

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

Create custom attributes

public class FileSizeAttribute : ValidationAttribute
{
    private readonly int _maxSize;

    public FileSizeAttribute(int maxSize)
    {
        _maxSize = maxSize;
    }
    //.....
    //.....
}



public class FileTypesAttribute : ValidationAttribute
{
    private readonly List<string> _types;

    public FileTypesAttribute(string types)
    {
        _types = types.Split(',').ToList();
    } 
    //....
    //...
}

And file length validation in asp.net core:

public async Task<IActionResult> MyAction()
{
    var form = await Request.ReadFormAsync();
    if (form.Files != null && form.Files.Count == 1)
    {
        var file = form.Files[0];
        if (file.Length > 1 * 1024 * 1024)
        {
            ModelState.AddModelError(String.Empty, "Maximum file size is 1 Mb.");
        }
    }
    // action code goes here
}