Here’s how I do a file upload on an ASP.Net MVC 4 page.
For this example, I’m using a controller named “HomeController”, with the view “Index”. When you click the “Submit” button on the view, it will be submitted to the “Save” method of HomeController.
Index.cshtml source code
Here’s the code for the view.
@using(Html.BeginForm("Save", "Home", FormMethod.Post, new {enctype = "multipart/form-data"})) { <table> <tr> <td>File:</td> <td> <input type="file" name="UploadedFile" /> </td> </tr> <tr> <td colspan="2"> <input type="submit" name="Submit" value="Submit"/> </td> </tr> </table> }
Notice the two additional parameters for BeginForm
FormMethod.Post, new {enctype = “multipart/form-data”}
You need those to have the file included in the HTTP Post action to the Save method on the controller.
Other than that, you just need a file input control, with a unique name attribute set.
HomeController view source code
Here’s the code to handle when the user submits the view page.
using System; using System.Web; using System.Web.Mvc; namespace FileUpload.Controllers { public class HomeController : Controller { public ActionResult Index() { return View(); } public ActionResult Save(FormCollection formCollection) { if(Request != null) { HttpPostedFileBase file = Request.Files["UploadedFile"]; if((file != null) && (file.ContentLength > 0) && !string.IsNullOrEmpty(file.FileName)) { string fileName = file.FileName; string fileContentType = file.ContentType; byte[] fileBytes = new byte[file.ContentLength]; file.InputStream.Read(fileBytes, 0, Convert.ToInt32(file.ContentLength)); } } return View("Index"); } } }
The Request object is a base object for handling HTTP requests. Since we set the FormMethod and enctype in the view, we have access to the file that was submitted on the page.
If the Request object isn’t null, we can check for the file by getting the HttpPostedFileBase from the Request object’s list of files, using its name (which is why a unique name was required for the file input control on the view).
Then we do some checking, to make sure the file actually has data, and get its information.
If you’re going to save the files somewhere (which is probably why you’re letting people upload files), then you’re going to need a way to display it for them later. To display a file within a browser, you need to know its ContentType. This will let the browser display it in the correct way.
With the byte array of the file’s contents, you can either save it to the database, in a varbinary column [for SQL Server], or write it out to disk, or some other document storage location.
Where you should save the files depends on what you’re going to do with them, how large they are, and what type of file they are.
EDIT: 28 April 2014
In the HomeController code, you’d add the “save” routine after line 25 (but still inside the “if” statement) – after you know you have a file with more than 0 bytes and after you’ve read the file stream.
The code to save the file isn’t here because there are several different ways you can save it, and several things you need to consider when deciding how and where to save the uploaded files.
For example:
- How large will the files be?
- How many files will the user upload to your website?
- Will the user be changing/overwriting the file?
- Do you need an audit log to track changes and/or previous versions of uploaded files?
- Does your network have any security requirements (many financial companies do)?
- What are you going to do to ensure the users don’t load any viruses or malicious executable code that could run on your server?
If it’s something small, such as a 10K jpeg a user wants to have as the avatar for their account profile, you might save the byte array to a varbinary column in the User table. It works the same as doing an insert or update of a string into a varchar column.
However, if you have someone uploading documents, or other types of files, you probably want to store them to a separate document server on your network. In the past, I’ve done that by writing a .Net remoting service on the document server. Nowadays, you might set up a WCF app on the document server.
WARNING: You don’t want to give your web app direct access to write files on another server in your network. That has the potential to be a big security problem.
Also, you definitely do not want to save the documents to your web server.
Besides being a serious security problem, experience has shown me that the network administrators will not be monitoring the amount of free disk space on your web server. You will eventually run out of disk on your web server and have another set of problems to deal with – including your website crashing.
Here’s a diagram of how you might have your network infrastructure set up for a document server. The web server is the only one visible to the Internet. You have your database server and document server behind a firewall – with rules that only let your website communicate with them.
