ASP.NET MVC 5 - Limit Upload File Size

This article is about uploading files by limiting/restricting the desired upload file size by implementing a custom data annotation/attribute component on ASP.NET MVC5 platform.

The size of an uploaded file is an important factor for considering the storage capacity. We cannot allow an infinite file size to be uploaded by the end-users because this will cause only one user to fill the server storage capacity in the worst case scenario. Well, that could cause a lot of issues at the back-end server. So, restricting or limiting the upload file size is one of the key business requirements of the 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 limiting/restricting of upload file size by implementing a 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.

 

Prerequisites

Following are some prerequisites before you proceed any further in this tutorial.

  1. Knowledge of ASP.NET MVC5
  2. Knowledge of HTML
  3. Knowledge of Bootstrap
  4. 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

Create a new MVC web project and name it "ImgFileSizeLimit".

Step 2

You need to add/update the values of "executionTimeout", "maxRequestLength" & "maxAllowedContentLength" properties if not already added in the "Web.config" file, as shown below.
  1.   .....  
  2.   
  3. <system.web>  
  4.   <authentication mode="None" />  
  5.   <compilation debug="true" targetFramework="4.5.2" />  
  6.   <!-- executionTimeout = 30hrs (the value is in seconds) and maxRequestLength = 1GB (the value is in Bytes) -->  
  7.   <httpRuntime targetFramework="4.5.2" executionTimeout="108000" maxRequestLength="1073741824" />  
  8. </system.web>     
  9. <system.webServer>  
  10.   <!-- maxAllowedContentLength = 1GB (the value is in Bytes) -->      
  11.   <security>  
  12.     <requestFiltering>  
  13.       <requestLimits maxAllowedContentLength="1073741824" />  
  14.     </requestFiltering>  
  15.   </security>          
  16.   
  17.   .....  
  18.   
  19. </system.webServer>  
  20.   
  21.   ..... 

executionTimeout -> The amount of time required to process your request on the web server; The value is provided in seconds.

maxRequestLength -> The maximum size which your request can capture and send to the web server; The value is provided in bytes.

maxAllowedContentLength -> The maximum allowed size of your content (e.g. file, text data etc) to be sent to the web server; The value is provided in bytes.

Step 3

Open the "Views->Shared->_Layout.cshtml" file and replace the code with the following code in it.

  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4.     <meta charset="utf-8" />  
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">  
  6.     <title>@ViewBag.Title</title>  
  7.     @Styles.Render("~/Content/css")  
  8.     @Scripts.Render("~/bundles/modernizr")  
  9.   
  10.     <!-- Font Awesome -->  
  11.     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" />  
  12.   
  13. </head>  
  14. <body>  
  15.     <div class="navbar navbar-inverse navbar-fixed-top">  
  16.         <div class="container">  
  17.             <div class="navbar-header">  
  18.                 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">  
  19.                     <span class="icon-bar"></span>  
  20.                     <span class="icon-bar"></span>  
  21.                     <span class="icon-bar"></span>  
  22.                 </button>  
  23.             </div>  
  24.         </div>  
  25.     </div>  
  26.     <div class="container body-content">  
  27.         @RenderBody()  
  28.         <hr />  
  29.         <footer>  
  30.             <center>  
  31.                 <p><strong>Copyright © @DateTime.Now.Year - <a href="http://wwww.asmak9.com/">Asma's Blog</a>.</strong> All rights reserved.</p>  
  32.             </center>  
  33.         </footer>  
  34.     </div>  
  35.   
  36.     @*Scripts*@  
  37.     @Scripts.Render("~/bundles/jquery")  
  38.   
  39.     @Scripts.Render("~/bundles/jqueryval")  
  40.     @Scripts.Render("~/bundles/bootstrap")  
  41.   
  42.     @RenderSection("scripts", required: false)  
  43. </body>  
  44. </html> 

In the above code, I have simply created a basic default layout page and linked the require libraries into it.

Step 4

Create a new "Helper_Code\Common\AllowFileSizeAttribute.cs" file and paste the following code in it.

  1. //-----------------------------------------------------------------------  
  2. // <copyright file="AllowFileSizeAttribute.cs" company="None">  
  3. //     Copyright (c) Allow to distribute this code and utilize this code for personal or commercial purpose.  
  4. // </copyright>  
  5. // <author>Asma Khalid</author>  
  6. //-----------------------------------------------------------------------  
  7.   
  8. namespace ImgFileSizeLimit.Helper_Code.Common  
  9. {  
  10.     using System;  
  11.     using System.Collections.Generic;  
  12.     using System.ComponentModel.DataAnnotations;  
  13.     using System.Linq;  
  14.     using System.Web;  
  15.   
  16.     /// <summary>  
  17.     /// Allow file size attribute class  
  18.     /// </summary>  
  19.     [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]  
  20.     public class AllowFileSizeAttribute : ValidationAttribute  
  21.     {  
  22.         #region Public / Protected Properties  
  23.   
  24.         /// <summary>  
  25.         /// Gets or sets file size property. Default is 1GB (the value is in Bytes).  
  26.         /// </summary>  
  27.         public int FileSize { getset; } = 1 * 1024 * 1024 * 1024;  
  28.  
  29.         #endregion  
  30.  
  31.         #region Is valid method  
  32.   
  33.         /// <summary>  
  34.         /// Is valid method.  
  35.         /// </summary>  
  36.         /// <param name="value">Value parameter</param>  
  37.         /// <returns>Returns - true is specify extension matches.</returns>  
  38.         public override bool IsValid(object value)  
  39.         {  
  40.             // Initialization  
  41.             HttpPostedFileBase file = value as HttpPostedFileBase;  
  42.             bool isValid = true;  
  43.   
  44.             // Settings.  
  45.             int allowedFileSize = this.FileSize;  
  46.   
  47.             // Verification.  
  48.             if (file != null)  
  49.             {  
  50.                 // Initialization.  
  51.                 var fileSize = file.ContentLength;  
  52.   
  53.                 // Settings.  
  54.                 isValid = fileSize <= allowedFileSize;  
  55.             }  
  56.   
  57.             // Info  
  58.             return isValid;  
  59.         }  
  60.  
  61.         #endregion  
  62.     }  

In ASP.NET MVC5, creating customized data annotations/attributes is one of the cool features. In the above code, I have created a new class "AllowFileSizeAttribute" (by following the naming convention of custom attribute class) and inherited ValidationAttribute class. Then, I have created a public property "FileSize" and set its default value as 1 GB in bytes which means that my custom attribute will accept only uploaded files with a maximum file size less than or equal to 1 GB. So, in order to allow the required file size, 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 size of the upload file and then validated whether it is less than or equal to the default file size restriction or according to my provided file size.

Step 5oi

Now, create a new "Models\ImgViewModel.cs" file and add the following code.

  1. //-----------------------------------------------------------------------  
  2. // <copyright file="ImgViewModel.cs" company="None">  
  3. //     Copyright (c) Allow to distribute this code and utilize this code for personal or commercial purpose.  
  4. // </copyright>  
  5. // <author>Asma Khalid</author>  
  6. //-----------------------------------------------------------------------  
  7.   
  8. namespace ImgFileSizeLimit.Models  
  9. {  
  10.     using System.Collections.Generic;  
  11.     using System.ComponentModel.DataAnnotations;  
  12.     using System.Web;  
  13.     using Helper_Code.Common;  
  14.   
  15.     /// <summary>  
  16.     /// Image view model class.  
  17.     /// </summary>  
  18.     public class ImgViewModel  
  19.     {  
  20.         #region Properties  
  21.   
  22.         /// <summary>  
  23.         /// Gets or sets Image file.  
  24.         /// </summary>  
  25.         [Required]  
  26.         [Display(Name = "Upload File")]  
  27.         [AllowFileSize(FileSize = 5 * 1024 * 1024, ErrorMessage = "Maximum allowed file size is 5 MB")]  
  28.         public HttpPostedFileBase FileAttach { getset; }  
  29.   
  30.         /// <summary>  
  31.         /// Gets or sets message property.  
  32.         /// </summary>  
  33.         public string Message { getset; }  
  34.   
  35.         /// <summary>  
  36.         /// Gets or sets a value indicating whether file size is valid or not property.  
  37.         /// </summary>  
  38.         public bool IsValid { getset; }  
  39.  
  40.         #endregion  
  41.     }  

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 the uploaded image/file data from the end-user. Then, I have also applied my custom "AllowFileSize" attribute to the FileAttach property and provided the default file size as 5 MB 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

Create a new "Controllers\ImgController.cs" file and add the following code.

  1. //-----------------------------------------------------------------------  
  2. // <copyright file="ImgController.cs" company="None">  
  3. //     Copyright (c) Allow to distribute this code and utilize this code for personal or commercial purpose.  
  4. // </copyright>  
  5. // <author>Asma Khalid</author>  
  6. //-----------------------------------------------------------------------  
  7.   
  8. namespace ImgFileSizeLimit.Controllers  
  9. {  
  10.     using System;  
  11.     using System.Collections.Generic;  
  12.     using System.Linq;  
  13.     using System.Web;  
  14.     using System.Web.Mvc;  
  15.     using Models;  
  16.   
  17.     /// <summary>  
  18.     /// Image controller class.  
  19.     /// </summary>  
  20.     public class ImgController : Controller  
  21.     {  
  22.         #region Index view method.  
  23.  
  24.         #region Get: /Img/Index method.  
  25.   
  26.         /// <summary>  
  27.         /// Get: /Img/Index method.  
  28.         /// </summary>          
  29.         /// <returns>Return index view</returns>  
  30.         public ActionResult Index()  
  31.         {  
  32.             // Initialization/  
  33.             ImgViewModel model = new ImgViewModel() { FileAttach = null, Message = string.Empty, IsValid = false };  
  34.   
  35.             try  
  36.             {  
  37.             }  
  38.             catch (Exception ex)  
  39.             {  
  40.                 // Info  
  41.                 Console.Write(ex);  
  42.             }  
  43.   
  44.             // Info.  
  45.             return this.View(model);  
  46.         }  
  47.  
  48.         #endregion  
  49.  
  50.         #region POST: /Img/Index  
  51.   
  52.         /// <summary>  
  53.         /// POST: /Img/Index  
  54.         /// </summary>  
  55.         /// <param name="model">Model parameter</param>  
  56.         /// <returns>Return - Response information</returns>  
  57.         [HttpPost]  
  58.         [AllowAnonymous]  
  59.         [ValidateAntiForgeryToken]  
  60.         public ActionResult Index(ImgViewModel model)  
  61.         {  
  62.             try  
  63.             {  
  64.                 // Verification  
  65.                 if (ModelState.IsValid)  
  66.                 {  
  67.                     // Settings.  
  68.                     model.Message = "'" + model.FileAttach.FileName + "' file has been successfuly!! uploaded";  
  69.                     model.IsValid = true;  
  70.                 }  
  71.                 else  
  72.                 {  
  73.                     // Settings.  
  74.                     model.Message = "'" + model.FileAttach.FileName + "' file size exceeds maximum limit. ";  
  75.                     model.IsValid = false;  
  76.                 }  
  77.             }  
  78.             catch (Exception ex)  
  79.             {  
  80.                 // Info  
  81.                 Console.Write(ex);  
  82.             }  
  83.   
  84.             // Info  
  85.             return this.View(model);  
  86.         }  
  87.  
  88.         #endregion  
  89.  
  90.         #endregion  
  91.     }  

In the above code, I have created the GET "Index(...)" method which will initialize the View Model with default values and sent it to the View page. Finally, I have created the POST "Index(...)" method which will receive an input file from the end-user, then validated the View Model for allowed file size and then sent the response message accordingly.

Step 7

Now, create a view "Views\Img\Index.cshtml" file and add the following lines to it.

  1. @using ImgFileSizeLimit.Models  
  2.   
  3. @model ImgFileSizeLimit.Models.ImgViewModel  
  4.   
  5. @{  
  6.     ViewBag.Title = "ASP.NET MVC5: Limit Upload File Size";  
  7. }  
  8.   
  9.   
  10. <div class="row">  
  11.     <div class="panel-heading">  
  12.         <div class="col-md-8">  
  13.             <h3>  
  14.                 <i class="fa fa-file-text-o"></i>  
  15.                 <span>ASP.NET MVC5: Limit Upload File Size</span>  
  16.             </h3>  
  17.         </div>  
  18.     </div>  
  19. </div>  
  20.   
  21. <br />  
  22.   
  23. <div class="row">  
  24.     <div class="col-md-6 col-md-push-2">  
  25.         <section>  
  26.             @using (Html.BeginForm("Index", "Img", FormMethod.Post, new { enctype = "multipart/form-data", @class = "form-horizontal"role = "form" }))  
  27.             {  
  28.                 @Html.AntiForgeryToken()  
  29.   
  30.                 <div class="well bs-component">  
  31.                     <br />  
  32.   
  33.                     <div class="row">  
  34.                         <div class="col-md-12">  
  35.                             <div class="col-md-8 col-md-push-2">  
  36.                                 <div class="input-group">  
  37.                                     <span class="input-group-btn">  
  38.                                         <span class="btn btn-default btn-file">  
  39.                                             Browse…  
  40.                                             @Html.TextBoxFor(m => m.FileAttach, new { type = "file"placeholder = Html.DisplayNameFor(m => m.FileAttach), @class = "form-control" })  
  41.                                         </span>  
  42.                                     </span>  
  43.                                     <input type="text" class="form-control" readonly>  
  44.                                 </div>  
  45.                                 @if (Model.IsValid && !string.IsNullOrEmpty(Model.Message))  
  46.                                 {  
  47.                                     <span class="text-success">@Model.Message</span>  
  48.                                 }  
  49.                                 else  
  50.                                 {  
  51.                                     <span class="text-danger">@Model.Message</span>@Html.ValidationMessageFor(m => m.FileAttach, "", new { @class = "text-danger" })  
  52.                                 }  
  53.                             </div>  
  54.                         </div>  
  55.                     </div>  
  56.   
  57.                     <div class="form-group">  
  58.                         <div class="col-md-12">  
  59.                         </div>  
  60.                     </div>  
  61.   
  62.                     <div class="form-group">  
  63.                         <div class="col-md-offset-5 col-md-10">  
  64.                             <input type="submit" class="btn btn-danger" value="Upload" />  
  65.                         </div>  
  66.                     </div>  
  67.                 </div>  
  68.             }  
  69.         </section>  
  70.     </div>  
  71. </div>  
  72.   
  73. @section Scripts  
  74. {  
  75.     @*Scripts*@  
  76.     @Scripts.Render("~/bundles/bootstrap-file")  
  77.   
  78.     @*Styles*@  
  79.     @Styles.Render("~/Content/Bootstrap-file/css")  

In the above code, I have created a simple View for uploading the file to the server which will validate the allowed file size at the server side.

Step 8

Now, execute the project and you will be able to see the following in action.

 

So, when I try to upload a file with a size greater than 5 MB, I will receive the error message like below.

Conclusion

In this article, we learned about limiting/restricting the desired upload file size by implementing custom data annotation/attribute component on ASP.NET MVC5 platform. Also, we saw how to create a custom data annotation/attribute class and then utilize the custom attribute in our View Model property of type HttpPostedFileBase.