Restricting or limiting the file type extensions is a key business requirement. It is not necessary that a business allows all file types to be uploaded via their web application. Sometimes, only image files are accepted by the web application, sometimes only documents, and sometimes the combination of image, documents, and compressed file types are accepted by the web system.
Today, I shall be demonstrating the process of limiting/restricting the desired upload file type extensions by implementing custom data annotation/attribute component on ASP.NET MVC5 platform. This article is not specific to image files only, you can use the provided solution with any type of file format as well.

Following are some prerequisites before you proceed any further in this tutorial.
- Knowledge of ASP.NET MVC5.
- Knowledge of HTML.
- Knowledge of Bootstrap.
- Knowledge of C# Programming.
You can download the complete source code for this tutorial or you can follow the step by step discussion below. The sample code is being developed in Microsoft Visual Studio 2015 Enterprise.
Let's begin now.
Step 1
Step 2
- .....
- <system.web>
- <authentication mode="None" />
- <compilation debug="true" targetFramework="4.5.2" />
- <!-- executionTimeout = 30hrs (the value is in seconds) and maxRequestLength = 1GB (the value is in Bytes) -->
- <httpRuntime targetFramework="4.5.2" executionTimeout="108000" maxRequestLength="1073741824" />
- </system.web>
- <system.webServer>
- <!-- maxAllowedContentLength = 1GB (the value is in Bytes) -->
- <security>
- <requestFiltering>
- <requestLimits maxAllowedContentLength="1073741824" />
- </requestFiltering>
- </security>
- .....
- </system.webServer>
- .....
executionTimeout -> Amount of time required to process your request on the web server. The value is provided in seconds.
maxRequestLength -> Maximum size which your request can capture and send to the web server. The value is provided in bytes.
maxAllowedContentLength -> Maximum allowed size of your content (e.g. file, text data etc.) that is sent to the web server. The value is provided in bytes.
Step 3
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>@ViewBag.Title</title>
- @Styles.Render("~/Content/css")
- @Scripts.Render("~/bundles/modernizr")
- <!-- Font Awesome -->
- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" />
- </head>
- <body>
- <div class="navbar navbar-inverse navbar-fixed-top">
- <div class="container">
- <div class="navbar-header">
- <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- </button>
- </div>
- </div>
- </div>
- <div class="container body-content">
- @RenderBody()
- <hr />
- <footer>
- <center>
- <p><strong>Copyright © @DateTime.Now.Year - <a href="http://wwww.asmak9.com/">Asma's Blog</a>.</strong> All rights reserved.</p>
- </center>
- </footer>
- </div>
- @*Scripts*@
- @Scripts.Render("~/bundles/jquery")
- @Scripts.Render("~/bundles/jqueryval")
- @Scripts.Render("~/bundles/bootstrap")
- @RenderSection("scripts", required: false)
- </body>
- </html>
In the above code, I have simply created a basic default layout page and linked the require libraries into it.
Step 4
- //-----------------------------------------------------------------------
- // <copyright file="AllowExtensionsAttribute.cs" company="None">
- // Copyright (c) Allow to distribute this code and utilize this code for personal or commercial purpose.
- // </copyright>
- // <author>Asma Khalid</author>
- //-----------------------------------------------------------------------
- namespace ImgExtLimit.Helper_Code.Common
- {
- using System;
- using System.Collections.Generic;
- using System.ComponentModel.DataAnnotations;
- using System.Linq;
- using System.Web;
- /// <summary>
- /// File extensions attribute class
- /// </summary>
- [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
- public class AllowExtensionsAttribute : ValidationAttribute
- {
- #region Public / Protected Properties
- /// <summary>
- /// Gets or sets extensions property.
- /// </summary>
- public string Extensions { get; set; } = "png,jpg,jpeg,gif";
- #endregion
- #region Is valid method
- /// <summary>
- /// Is valid method.
- /// </summary>
- /// <param name="value">Value parameter</param>
- /// <returns>Returns - true is specify extension matches.</returns>
- public override bool IsValid(object value)
- {
- // Initialization
- HttpPostedFileBase file = value as HttpPostedFileBase;
- bool isValid = true;
- // Settings.
- List<string> allowedExtensions = this.Extensions.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
- // Verification.
- if (file != null)
- {
- // Initialization.
- var fileName = file.FileName;
- // Settings.
- isValid = allowedExtensions.Any(y => fileName.EndsWith(y));
- }
- // Info
- return isValid;
- }
- #endregion
- }
- }
In ASP.NET MVC 5, creating customized data annotations/attributes is one of the cool features. The ASP.NET MVC 5 platform already contains a default FileExtensions attribute, but, the issue with this pre-built data annotation/attribute is that it is applicable only on string type view model properties and in my case, I am uploading the files via "HttpPostedFileBase" data type view model property. This means that the pre-built data annotation/attribute does not have any means to know the data type of the file(s) that I am uploading which will have no effect on the limitation that is considered to be applied on the uploaded file type extensions. Of course, there are many other tricks or workarounds to go through while working with the pre-built FileExtensions attribute, but, I prefer the custom data annotation/attribute mechanism, which is much simpler.
So, in the above code, I have created a new class "AllowExtensionsAttribute" (by following the naming convention of custom attribute class) and inherited the ValidationAttribute class. Then, I have created a public property "Extensions" and set the default value with image file type extensions, which means that my custom attribute will accept only image file type to be uploaded. So, in order to allow the required file type extensions, this property will be updated at the time of my custom attribute utilization accordingly. Finally, I have overridden the "IsValid(....)" method which will receive my uploaded file as "HttpPostedFileBase" data type and from this, I will extract the file type extension of the uploaded file and then validate whether it is according to either default file type extension restriction or according to my provided file type extensions.
Step 5
- //-----------------------------------------------------------------------
- // <copyright file="ImgViewModel.cs" company="None">
- // Copyright (c) Allow to distribute this code and utilize this code for personal or commercial purpose.
- // </copyright>
- // <author>Asma Khalid</author>
- //-----------------------------------------------------------------------
- namespace ImgExtLimit.Models
- {
- using System.Collections.Generic;
- using System.ComponentModel.DataAnnotations;
- using System.Web;
- using Helper_Code.Common;
- /// <summary>
- /// Image view model class.
- /// </summary>
- public class ImgViewModel
- {
- #region Properties
- /// <summary>
- /// Gets or sets Image file property.
- /// </summary>
- [Required]
- [Display(Name = "Supported Files .png | .jpg")]
- [AllowExtensions(Extensions = "png,jpg", ErrorMessage = "Please select only Supported Files .png | .jpg")]
- public HttpPostedFileBase FileAttach { get; set; }
- /// <summary>
- /// Gets or sets message property.
- /// </summary>
- public string Message { get; set; }
- /// <summary>
- /// Gets or sets is valid propertty.
- /// </summary>
- public bool isValid { get; set; }
- #endregion
- }
- }
In the above code, I have created my view model which I will attach with my view. Here, I have created HttpPostedFileBase type file attachment property which will capture uploaded image/file data from the end-user, then I have also applied my custom "AllowExtensions" attribute to the FileAttach property and provide the list of file type extensions separated by a comma (,) that I have allowed my system to accept. Then, I have created two more properties; i.e., Message of data type string and isValid of data type Boolean for processing purpose.
Step 6
- //-----------------------------------------------------------------------
- // <copyright file="ImgController.cs" company="None">
- // Copyright (c) Allow to distribute this code and utilize this code for personal or commercial purpose.
- // </copyright>
- // <author>Asma Khalid</author>
- //-----------------------------------------------------------------------
- namespace ImgExtLimit.Controllers
- {
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
- using Models;
- /// <summary>
- /// Image controller class.
- /// </summary>
- public class ImgController : Controller
- {
- #region Index view method.
- #region Get: /Img/Index method.
- /// <summary>
- /// Get: /Img/Index method.
- /// </summary>
- /// <returns>Return index view</returns>
- public ActionResult Index()
- {
- // Initialization/
- ImgViewModel model = new ImgViewModel() { FileAttach = null, Message = string.Empty, isValid = false };
- try
- {
- }
- catch (Exception ex)
- {
- // Info
- Console.Write(ex);
- }
- // Info.
- return this.View(model);
- }
- #endregion
- #region POST: /Img/Index
- /// <summary>
- /// POST: /Img/Index
- /// </summary>
- /// <param name="model">Model parameter</param>
- /// <returns>Return - Response information</returns>
- [HttpPost]
- [AllowAnonymous]
- [ValidateAntiForgeryToken]
- public ActionResult Index(ImgViewModel model)
- {
- try
- {
- // Verification
- if (ModelState.IsValid)
- {
- // Settings.
- model.Message = "'" + model.FileAttach.FileName + "' file has been successfuly!! uploaded";
- model.isValid = true;
- }
- else
- {
- // Settings.
- model.Message = "'" + model.FileAttach.FileName + "' file is not supported. ";
- model.isValid = false;
- }
- }
- catch (Exception ex)
- {
- // Info
- Console.Write(ex);
- }
- // Info
- return this.View(model);
- }
- #endregion
- #endregion
- }
- }
In the above code, I have created a GET "Index(...)" method which will initialize the view model with default values and send it to the view page. Finally, I have created a POST "Index(...)" method which will receive an input image file from the end-user, then validate the view model for allowed file type extensions and then send the response message accordingly.
Step 7
- @using ImgExtLimit.Models
- @model ImgExtLimit.Models.ImgViewModel
- @{
- ViewBag.Title = "ASP.NET MVC5: Limit Upload File Extension";
- }
- <div class="row">
- <div class="panel-heading">
- <div class="col-md-8">
- <h3>
- <i class="fa fa-file-text-o"></i>
- <span>ASP.NET MVC5: Limit Upload File Extension</span>
- </h3>
- </div>
- </div>
- </div>
- <br />
- <div class="row">
- <div class="col-md-6 col-md-push-2">
- <section>
- @using (Html.BeginForm("Index", "Img", FormMethod.Post, new { enctype = "multipart/form-data", @class = "form-horizontal", role = "form" }))
- {
- @Html.AntiForgeryToken()
- <div class="well bs-component">
- <br />
- <div class="row">
- <div class="col-md-12">
- <div class="col-md-8 col-md-push-2">
- <div class="input-group">
- <span class="input-group-btn">
- <span class="btn btn-default btn-file">
- Browse…
- @Html.TextBoxFor(m => m.FileAttach, new { type = "file", placeholder = Html.DisplayNameFor(m => m.FileAttach), @class = "form-control" })
- </span>
- </span>
- <input type="text" class="form-control" readonly>
- </div>
- @if (Model.isValid && !string.IsNullOrEmpty(Model.Message))
- {
- <span class="text-success">@Model.Message</span>
- }
- else
- {
- <span class="text-danger">@Model.Message</span>@Html.ValidationMessageFor(m => m.FileAttach, "", new { @class = "text-danger" })
- }
- </div>
- </div>
- </div>
- <div class="form-group">
- <div class="col-md-12">
- </div>
- </div>
- <div class="form-group">
- <div class="col-md-offset-5 col-md-10">
- <input type="submit" class="btn btn-danger" value="Upload" />
- </div>
- </div>
- </div>
- }
- </section>
- </div>
- </div>
- @section Scripts
- {
- @*Scripts*@
- @Scripts.Render("~/bundles/bootstrap-file")
- @*Styles*@
- @Styles.Render("~/Content/Bootstrap-file/css")
- }
In the above code, I have created a simple view for uploading the image file to the server which will validate the allowed file type extensions at the server side.
Step 8





Conclusion
In this article, you learned about uploading of the image file by limiting/restricting the desired upload file type extensions by implementing custom data annotation/attribute component on ASP.NET MVC5 platform. We also learned how to create a custom data annotation/attribute class and then utilize the custom attribute in your view model property of type HttpPostedFileBase.

sunny kumarPosted Jan 15, 2020, 10:16 PM
Using System;using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Web; namespace WebApplication2.Models { public class TourDetailModels { [Key] public int id { get; set; } [Required] [Display(Name ="Subject")] public string Subject { get; set; } [Required] [Display(Name = "Tour Date")] public string TourYear { get; set; } [Required] [Display(Name = "Total Foreign Tours")] public int ForeignTourCount { get; set; } [Required] [Display(Name = "Country")] public string Country { get; set; } public string OfficerName { get; set; } [Display(Name = "Status")] public string Tourstatus { get; set; } public DateTime timestamp { get; set; } [Display(Name = "Data Filled By")] public string DataFilledBy { get; set; } public string filename { get; set; } public string PptAfterTour { get; set; } public string filenameaftertour { get; set; } public string PptBeforeTour { get; set; } public int status { get; set; } = 1; [NotMapped] [Required] [Helper(Extensions ="pdf,ppt",ErrorMessage ="Please Upload Only Specific Extension Files")] public HttpPostedFileBase pptbeforetourpath { get; set; } //[NotMapped] //[Required] //[ValidateFile] //public HttpPostedFileBase pptaftertourpath { get; set; } } }
sunny kumarPosted Jan 15, 2020, 10:16 PM
Using System;using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Web; namespace WebApplication2.Models { [AttributeUsage(AttributeTargets.Field|AttributeTargets.Property,AllowMultiple =false,Inherited =true)] public class Helper:ValidationAttribute { public string Extensions { get; set; } = "pdf,ppt"; public override bool IsValid(object value) { HttpPostedFileBase file = value as HttpPostedFileBase; bool isValid = true; List<string> allowedExtensions = this.Extensions.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(); if (file != null) { var filename = file.FileName; isValid = allowedExtensions.Any(y => filename.EndsWith(y)); } return isValid; } } }
sunny kumarPosted Jan 15, 2020, 10:16 PM
I also tried your code, but still it is getting passed through the model validation, i dont know how
Kuldeep SinghPosted Apr 6, 2019, 4:04 PM
It it working fine on server side. Mam can you provide or extend this code for working on client side as well.