In this article, we are going to learn how to create dynamic file upload and validate all files in MVC. If you Google for file upload examples in MVC, you will find many examples but all are for single file uploads. Here, we don’t want that. We want to generate dynamic file upload on the basis of condition.
You can think of it as tailored file uploads
E.g. if a user is filling out a form for a new driving license, he is required to upload documents, like address proof [Passport] and personal identity etc. But meanwhile, if you are applying for a passport, then you may need a driving license and personal identity. For developing this, we are not going to create 2 different pages but we are going to create it dynamically, on a single page.
Fig 1 Multiple file uploads.
Tools Required
- SQL Server
- Visual Studio 2010 and above with MVC installed.
Creating Multiple Uploads
Let's start with creating a basic MVC application
From Visual Studio IDE, select File Menu right at the top. Inside that, select New --> Project and click on Project.
After selecting Project sub menu, a new dialog will pop up with the name “New Project”. In this dialog, first we select template from the left panel. First select "web" in the left panel, then choose “ASP.NET MVC 4 Web Application”. Now, name your project as “MultipleUploads”.
Fig 2. Selecting Template
Finally, click on OK button to create the project.
Selecting Templates
After you create a project, a new window will pop up with the name “New ASP.NET MVC 4 Project”. In this project template, just select Empty Template and in the View Engine, select Razor. Click on OK button.
Fig 3. Selecting MVC 4 Project
After a few seconds, you project is ready to go. It contains a whole lot of MVC folder structures and other scripts and .CSS styles.
Project Structure after creation
Fig 4. Project structure
Now, let’s start with adding Controller.
Adding Controller
After creating project, we are going to add Controller with the name DocumentsController which is going to handle http get [HttpGet] and post [HttpPost] requests.
Fig 5. Adding Documents Controller
After adding Controller, next we are going to add Model.
Adding Model
In this step, we are going to add Model with the name “DocumentModel”. This model will have properties, such as DocumentID, DocumentName, and Mandatory.
For adding Model, just right click on Models folder and select Add >> Class.
Fig 6. Adding DocumentModel
After selecting Class, a new dialog will pop up with the name “Add New Item”. Here, the class will be selected by default. All we need to do is give name to the class. We are going to name it as “DocumentModel”.
Fig 7. Adding DocumentModel
Code snippet of DocumentModel
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
-
- namespace MultipleUploads.Models
- {
- public class DocumentModel
- {
- public int DocumentID { get; set; }
- public string DocumentName { get; set; }
- public int Mandatory { get; set; }
- public List<DocumentModel> DocumentList { get; set; }
- }
- }
Properties - DocumentID is unique ID.
- DocumentName is the name of document which we are going to show to users to provide input.
- Mandatory is property which tells this file is Mandatory to upload or not.
- DocumentList contains the list of documents which we are going to send to View to generate controls.
After adding Model, next we are going to change the Action Method name inside Document Controller to “Upload” from Index; and create another action method which is going to handle http post [HttpPost] request, and will take DocumentModel as input parameter.
Code snippet of Document Controller
- using MultipleUploads.Models;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
-
- namespace MultipleUploads.Controllers
- {
- public class DocumentsController : Controller
- {
-
-
- [HttpGet]
- public ActionResult Upload()
- {
- return View();
- }
-
- [HttpPost]
- public ActionResult Upload(DocumentModel DocumentModel)
- {
- return View();
- }
- }
- }
After creating action method for handling both get and post methods, now we are going to fill collection of documents in http get request.
Populating Document Collection
In this step, we are going to fill collection which we are going to send to the View. Using this collection, we are going to create file upload controls on View.
Note: for displaying demo, I am going to fill collection in controller. If you want to populate this data from database, you can do it.
Code snippet of Document Controller
- using MultipleUploads.Models;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
-
- namespace MultipleUploads.Controllers
- {
- public class DocumentsController : Controller
- {
-
-
- [HttpGet]
- public ActionResult Upload()
- {
- DocumentModel objdocument = new DocumentModel();
-
- objdocument.DocumentList = new List<DocumentModel>
- {
- new DocumentModel { DocumentID = 1,DocumentName ="PANCard", Mandatory=1 },
- new DocumentModel { DocumentID = 2,DocumentName ="IncomeTax", Mandatory=0},
- new DocumentModel { DocumentID = 3,DocumentName ="PassPortID", Mandatory=1 },
- new DocumentModel { DocumentID = 4,DocumentName ="Driving_Licence", Mandatory=1 }
- };
-
- return View(objdocument);
- }
-
- [HttpPost]
- public ActionResult Upload(DocumentModel DocumentModel)
- {
- return View();
- }
- }
- }
After completing with filling collection, now let’s View.
Adding View
For adding View, just right click inside upload Action Method and then select Add View from List.
Fig 8. Adding upload View After selecting, a new dialog will pop up with the name “Add View”. This View will have same name as Action Method name, as shown in the below snapshot. After that, we are going to choose View engine as Razor (CSHTML), then we have a checkbox to choose which is used for creating strongly typed View. Here, it asks for choosing model class. We are going to choose DocumentModel which is a Model that we have created. We have scaffolding template option to choose. Here, we are just going to keep it empty and then finally, we have to click on Add button to create View.
Fig 9. Creating upload View Project Structure after adding View
Fig 10. Project structure after adding upload View After adding View, now we write the code on View to create multiple file upload controls.
Adding multiple file upload controls on View
In this step, we are going to generate multiple file upload control. For doing that, we use DocumentList model property which we are sending from Controller.
Code snippet
- @model MultipleUploads.Models.DocumentModel
- @ {
- Layout = null;
- }
- Model which is going to received upload View.
- Code snippet
- @using(Html.BeginForm("Upload", "Documents", FormMethod.Post, new {
- enctype = "multipart/form-data"
- })) {}
Html.BeginForm helper generates form tag and we have specified action name and controller name. Along with that, we are going to post this data. For that, we have used [ FormMethod.Post] method and at last enctype attribute to encoded data.
Note: The enctype attribute specifies how the form-data should be encoded when submitting it to the server.
Code snippet of upload View
- if (Model.DocumentList != null)
- {
- for (int i = 0; i < Model.DocumentList.Count; i++)
- {
- var fileupload1 = "file_" + Convert.ToString(Model.DocumentList[i].DocumentID);
- var hdnlbl1 = "hdnlbl_" + Convert.ToString(Model.DocumentList[i].DocumentID);
- var hdn1 = "hdn1_" + Convert.ToString(Model.DocumentList[i].DocumentID);
- var madname = "manddocname_" + Convert.ToString(Model.DocumentList[i].DocumentID);
- var valdation = "_val" + Convert.ToString(Model.DocumentList[i].DocumentID);
-
-
- if (Model.DocumentList[i].Mandatory != null)
- {
- var mad = "mand_" + i;
- @Html.HiddenFor(m => m.DocumentList[i].Mandatory, new { id = mad })
- }
-
- @{ var documentname = Model.DocumentList[i].DocumentName;}
-
-
- @Html.HiddenFor(m => m.DocumentList[i].DocumentName, new { id = hdnlbl1 })
- @Html.HiddenFor(m => m.DocumentList[i].DocumentID, new { id = hdn1 })
- @Html.HiddenFor(m => m.DocumentList[i].DocumentName, new { id = madname })
-
- <div class="row">
- <div class="col-md-3">
- @if (Model.DocumentList[i].Mandatory == 1)
- {
- <label style="color: red;">*</label>
- }
-
- <label style="font-size: 15px;">@documentname</label>
- <span class="btn btn-info btn-file">
- <input type="file" id="@fileupload1" name="@fileupload1"
- onchange="ValidateFile(this);" />
- </span>
- <span style="color:Red" id=@valdation></span>
-
- </div>
- </div>
- <br />
- }
- }
In this part, we are going to check if the Model which we are going to send is Null or not. After that, we use for loop to iterate and generate file upload control for list of documents sent from upload Action method [httpGet].
- if (Model.DocumentList != null)
- {
- for (int i = 0; i < Model.DocumentList.Count; i++)
- {
-
- }
- }
Then, we are generating unique id for assigning to controls because we should have unique id generated for each control to recognize it.
- var fileupload1 = "file_" + Convert.ToString(Model.DocumentList[i].DocumentID);
- var hdnlbl1 = "hdnlbl_" + Convert.ToString(Model.DocumentList[i].DocumentID);
- var hdn1 = "hdn1_" + Convert.ToString(Model.DocumentList[i].DocumentID);
- var madname = "manddocname_" + Convert.ToString(Model.DocumentList[i].DocumentID);
- var valdation = "_val" + Convert.ToString(Model.DocumentList[i].DocumentID);
After generating unique id, we are going to assign this id to hidden fields which will help us receive data at Action method level after post data to Server.
- if (Model.DocumentList[i].Mandatory != null)
- {
- var mad = "mand_" + i;
- @Html.HiddenFor(m => m.DocumentList[i].Mandatory, new { id = mad })
- }
-
- @{ var documentname = Model.DocumentList[i].DocumentName;}
-
-
- @Html.HiddenFor(m => m.DocumentList[i].DocumentName, new { id = hdnlbl1 })
- @Html.HiddenFor(m => m.DocumentList[i].DocumentID, new { id = hdn1 })
- @Html.HiddenFor(m => m.DocumentList[i].DocumentName, new { id = madname })
After assigning value to hidden fields, now we are going to create file upload control, label for displaying document name, and also we are showing asterisk mark if document id mandatory.
- <div class="row">
- <div class="col-md-3">
- @if (Model.DocumentList[i].Mandatory == 1)
- {
- <label style="color: red;">*</label>
- }
- @{ var documentname = Model.DocumentList[i].DocumentName;}
- <label style="font-size: 15px;">@documentname</label>
- <span class="btn btn-info btn-file">
- <input type="file" id="@fileupload1" name="@fileupload1"
- onchange="ValidateFile(this);" />
- </span>
- <span style="color:Red" id=@valdation></span>
-
- </div>
- </div>
- Finally we require submit but to post form to server.
- <div style="margin-top: 20px;" class="col-sm-4 col-xs-12 col-lg-6 col-md-4">
-
- <input id="Submit1" class="btn btn-success" type="submit"
- onclick="return Savefiles();" value=" submit" />
-
- </div>
Code snippet of upload View - <div class="container">
- <div style="margin-top: 20px;" class="row">
- <div class="col-sm-4 col-xs-12 col-lg-6 col-md-4">
- </div>
- </div>
- <div class="panel panel-default">
- <div class="panel-heading">@Html.Label("Upload Documents")</div>
- <div class="panel-body">
- @using (Html.BeginForm("Upload", "Documents", FormMethod.Post,
- new { id = "TheForm", enctype = "multipart/form-data" }))
- {
- if (Model.DocumentList != null)
- {
- for (int i = 0; i < Model.DocumentList.Count; i++)
- {
- var fileupload1 = "file_" + Convert.ToString(Model.DocumentList[i].DocumentID);
- var hdnlbl1 = "hdnlbl_" + Convert.ToString(Model.DocumentList[i].DocumentID);
- var hdn1 = "hdn1_" + Convert.ToString(Model.DocumentList[i].DocumentID);
-
- if (Model.DocumentList[i].Mandatory != null)
- {
- var mad = "mand_" + i;
- @Html.HiddenFor(m => m.DocumentList[i].Mandatory, new { id = mad })
- }
-
- var madname = "manddocname_" + Convert.ToString(Model.DocumentList[i].DocumentID);
- var valdation = "_val" + Convert.ToString(Model.DocumentList[i].DocumentID);
-
- @Html.HiddenFor(m => m.DocumentList[i].DocumentName, new { id = hdnlbl1 })
- @Html.HiddenFor(m => m.DocumentList[i].DocumentID, new { id = hdn1 })
- @Html.HiddenFor(m => m.DocumentList[i].DocumentName, new { id = madname })
-
- <div class="row">
- <div class="col-md-3">
- @if (Model.DocumentList[i].Mandatory == 1)
- {
- <label style="color: red;">*</label>
- }
- @{ var documentname = Model.DocumentList[i].DocumentName;}
- <label style="font-size: 15px;">@documentname</label>
- <span class="btn btn-info btn-file">
- <input type="file" id="@fileupload1" name="@fileupload1"
- onchange="ValidateFile(this);" />
- </span>
- <span style="color:Red" id=@valdation></span>
-
- </div>
- </div>
- <br />
- }
- }
- <div class="row">
- <div class="col-sm-4 col-xs-12 col-lg-6 col-md-4">
- </div>
- </div>
- <div style="margin-top: 20px;" class="col-sm-4 col-xs-12 col-lg-6 col-md-4">
- <input id="Submit1" class="btn btn-success" type="submit" onclick="return Savefiles();" value=" submit" />
- </div>
- }
- </div>
- </div>
- </div>
After we have generated control, let's have a look at how it gets rendered on the browser.
Fig 11. Upload View Rendered in browser
Now, we have just generated controls but we are not done with validation yet. So, let’s get started with it.
Validating File upload controls
For doing validation, we are going to use JavaScript.
- We are going to check file extension [is this file .png ,jpg, jpeg, .pdf]
- Size of file which is uploaded [Must be under 1 MB]
- Is file mandatory [the file declare as mandatory id must to upload]
Now, for doing this stuff, we need jQuery library.
Download: http://code.jquery.com/jquery-1.9.1.js
Download: http://code.jquery.com/jquery-migrate-1.2.1.js
We are going to validate file first. For doing this, we have used onchange event of JavaScript, when any one selects a file, this event gets called and mean while it is sending selected file upload id to the function.
After function receives file upload id, it will call another function [getNameFromPath] which returns file path. Now, from file path, we are going to extract extension and check if the extension is valid or not. If not, then we display error Message [You can upload only jpg, jpeg, png, pdf extension file Only] else we are going check size of the file uploaded by calling a function [ValidateFileSize]. If this is also not valid, then show the message [You Can Upload file Size Up to 1 MB] and then, remove the selected file.
- <input type="file" id="@fileupload1" name="@fileupload1" onchange="ValidateFile(this);" />
Complete Code Snippet for validating uploaded file,
- function ValidateFile(value)
- {
-
- var file = getNameFromPath($(value).val());
- if (file != null) {
- var extension = file.substr((file.lastIndexOf('.') + 1));
- switch (extension) {
- case 'jpg':
- case 'jpeg':
- case 'png':
- case 'pdf':
- flag = true;
- break;
- default:
- flag = false;
- }
- }
-
- if (flag == false)
- {
-
- var str = value.name;
- var res = str.split("_");
- var data = "_val" + res[1];
- $("#" + data).text("You can upload only jpg, jpeg, png, pdf extension file Only");
- $("#" + value.name).val('');
- return false;
- }
- else
- {
- var size = ValidateFileSize(value);
- var str = value.name;
- var res = str.split("_");
- var data = "_val" + res[1];
- if (size > 1)
- {
- $("#" + data).text("You Can Upload file Size Up to 1 MB.");
- $("#" + value.name).val('');
- }
- else
- {
- $("#" + data).text("");
- }
- }
- }
Complete Code Snippet for getting file name of uploaded file,
- function getNameFromPath(strFilepath)
- {
- var objRE = new RegExp(/([^\/\\]+)$/);
- var strName = objRE.exec(strFilepath);
-
- if (strName == null) {
- return null;
- }
- else {
- return strName[0];
- }
- }
Complete Code Snippet for getting file size of uploaded file,
- function ValidateFileSize(fileid) {
- try {
- var fileSize = 0;
- if (navigator.userAgent.match(/msie/i)) {
- var obaxo = new ActiveXObject("Scripting.FileSystemObject");
- var filePath = $("#" + fileid)[0].value;
- var objFile = obaxo.getFile(filePath);
- var fileSize = objFile.size;
- fileSize = fileSize / 1048576;
- }
- else {
- fileSize = $(fileid)[0].files[0].size
- fileSize = fileSize / 1048576;
- }
-
- return fileSize;
- }
- catch (e) {
- alert("Error is :" + e);
- }
- }
After validating all files, finally on submit button we are going to check if mandatory files are uploaded or not.
- <input id="Submit1" class="btn btn-success" type="submit" onclick="return Savefiles();"
- value=" submit" />
- Complete Code for checking mandatory files
- <script type="text/javascript">
-
- function Savefiles() {
- var MandFlg = $("[id*='mand_']");
- var FileUpload1 = $("[id*='file_']");
- var madfile = $("[id*='manddocname_']");
- var Booleandata = true;
- for (var i = 0; i < MandFlg.length; i++) {
- if ($("#" + MandFlg[i].id).val() == '1' && $("#" + FileUpload1[i].id).val() == '') {
- Booleandata = false;
- alert("Required " + $("#" + madfile[i].id).val());
- }
- }
- return Booleandata;
- }
-
- </script>
Fig 12. Upload View with all functionality Now, if everything is valid, then it will post form to the server else it will show error message.
After posting form, “upload” [HttpPost] action method will get called and it will receive all files which are posted, as shown below.
Fig 13. Posted data from View to Upload Action method
In upload action method, we are just going to receive files and according to our requirement we are going to store this file. If someone wants to save the files in a folder, they can do that. Meanwhile if some one wants in bytes, they too can store bytes in database.
Complete Code snippet of upload [HttpPost] Action Method.
- [HttpPost]
- public ActionResult Upload(DocumentModel DocumentModel)
- {
- var DocumentUpload = DocumentModel.DocumentList;
- foreach (var Doc in DocumentUpload)
- {
- string strFileUpload = "file_" + Convert.ToString(Doc.DocumentID);
- HttpPostedFileBase file = Request.Files[strFileUpload];
-
- if (file != null && file.ContentLength > 0)
- {
-
- var fileName = Path.GetFileName(file.FileName);
- var path = Path.Combine(Server.MapPath("~/Images/"), fileName);
- file.SaveAs(path);
-
-
- byte[] image = new byte[file.ContentLength];
- file.InputStream.Read(image, 0, image.Length);
-
- }
- }
- return View(DocumentModel);
- }
Thanks for taking the time to read this article.