Uploading and downloading files are common functions you’ll see in most websites and apps. Fortunately, it’s easy to write code to upload and download files using ASP.NET MVC. To start, we need a view and controller pair to upload a file. This is the same HTML and MVC code that you already know. However, there is no need for the model portion of the MVC pattern if you are only uploading files to disk and not working with a database. Otherwise, files can be a property of a model, for example, a profile picture.
Using Helpers is a great way to take advantage of built in features of the ASP.NET MVC framework such as accessing routing information to create a link or using strongly typed objects to render HTML. In the case of the Html.BeginForm helper, we are rendering a <form> element. The Html.BeginForm helper expects an enctype attribute that designates that the form can send binary data as well as textual data in the HTTP POST request. Since the default encoding type is “text-plain” the HTTP Request will not send binary data (that means files!) to the server along with the usual textual form data, so you must set the enctype attribute to multipart/form data or it will not work!
When the user clicks the submit button, it causes an HTTP POST submission to /Home/Upload, which maps to the Home Controller’s Upload action method. The Upload action method receives the file and form data and from there you can perform the actual upload and save the file to disk or put in the cloud.
Action methods of MVC Controllers accept incoming HTTP requests for processing. Each HTTP request has a certain way, or method (POST GET PUT DELETE etc..) that it sends data to the server. The receiving action method must expect that type of request in order to process it. Since HTTP GET is the default, you must apply the HttpPost attribute to the Upload action method. This, of course, matches the method=”post” attribute of the HTML <form> element.
You can access uploaded files in the action method by querying the argument that is of type HttpPostedFileBase . The name of this argument, “file” in the below sample, must match the name of its corresponding file input in the HTML form (i.e., <input type=”file” name=”file”>). This allows ASP.NET MVC’s model binding to occur for file uploads. Ensuring the names match is using a concept called Convention over Configuration and leads to more readable code.
If you need to upload multiple files, use IEnumerable<HttpPostedFileBase> instead of a single HttpPostedFile and loop through the collection to access individual files. When completing an upload, be sure that you have the correct permissions to write to the directory you want, then use classes from System.IO to access the file system and save the file.
System.IO.Path.GetFileName retrieves a file name including its extension, and System.IO.Path.Combine combines two or more strings to create a complete path. Because we’re working with an uploaded file from HTTP, we need Server.MapPath to map a virtual path (HTTP) to a physical directory (C:) . In this case the mapping is from the webroot, i.e., “~/” to the <project root>App_DataImages directory. I’m saving files to the App_Data directory to demonstrate concepts, but in real world sites it is unlikely that internet users would have privileges to save files there, so check with your sys admin or Web hoster as to where you should upload and download files.
If you are using Convention over Configuration then model binding will take care of everything and all you do is access the method’s arguments.
In order to download, we need the same MVC components – a view and a controller. We’ll start at the controller.
Usually the UI presents a list or grid of links or images in which the user can click to download an image or file. What we’ll use for this example is a simple list of links of images to download. We can do this by creating a List<string> to store the file names in hyperlinks for download. The code below shows obtaining the directory and file information and adding the file names to the list of strings. The method then returns the list of strings as a model to the view.
The view accepts the list of strings and displays them in the page.
Notice that the model for this view is a List<string> type instead of a custom object as usual. Of course, this the view consists of a simple for loop that cycles through a list of strings containing the file names and displays them in <label> and <a> tags. The hyperlinks render so that they point to the Home controller’s Download action method, and pass in the name of the file as a URL parameter. Cycling through a list of strings means that you can use array syntax (i.e., @Model[i]) to access each member in the list.
The image below is what the download view produces. The ActionLink Helper renders links that point to the Home controller’s Download action method, passing in the image name as a query string. I’m using the defaults but you might want to consider configuring Routing so that the URL looks friendlier.
FileContentResult : Use this when want to use a byte array to access the file. In this scenario, you might have obtained the file as a byte array from a database call.
FilePathResult : Returns a file on disk when you must access via a file path. In the FilePathResult you can return a File type or a FileStreamResult.
FileStreamResult : Sends a stream out to the response.
The various ways to return a file are very similar but allow sufficient customizations to meet the needs of most scenarios. Sometimes the file is from a stream or byte array, or sometimes you only have a simple file path. Media types as well as the System.Net.Mime.MediaTypeNames enum are available so you can designate the file type for download, as the above samples demonstrate.
Code for uploading and downloading files are mandatory tasks for Web developers at some point in time. We want to allow users to safely upload and download files to go along with other data, and using ASP.NET MVC means you can use Html Helpers as an easy way to provide this functionality.