Upload Files With Progress Using Uploadify
I recently posted an in depth tutorial on how to on upload multiple files using Uploadify.
The ASP.NET default handler for file uploads does not easily allow you to provide feedback or control over the process. There are many ways to work around this issue. In this blog I will explore using a Uploadify. Straight from their website:
Uploadify is a jQuery plugin that allows the easy integration of a multiple (or single) file uploads on your website. It requires Flash and any backend development language. An array of options allow for full customization for advanced users, but basic implementation is so easy that even coding novices can do it.
Uploadify is very easy to use. Here is a demo page.
Controller Code
The controller code is very simple.
public class UploadifyController : Controller { public ActionResult Index() { return View(); } public string Upload(HttpPostedFileBase file) { // Process the file here. // return "Upload processed. filename=" + file.FileName; } }
That is all that you need to handle the files posted by the control. The control can post multiple files simultaneously, so the ‘Upload’ action method should be designed accordingly. Once a file is completely uploaded, the Uploadify plugin will call the ‘Upload’ method with the HttpPostedFileBase as a parameter. The parameter name is configured in the JavaScript (see below).
View Code
The following view is a minimal example:
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title>A Minimal Uploadify Example</title> <script type="text/javascript" src="<%= Url.Content("~/Scripts/jquery-1.3.2.min.js") %>"></script> <script type="text/javascript" src="<%= Url.Content("~/Scripts/uploadify/swfobject.js") %>"></script> <script type="text/javascript" src="<%= Url.Content("~/Scripts/uploadify/jquery.uploadify.v2.1.0.js") %>"></script> </head> <body> <input type="file" name="fileInput1" id="fileInput1" /> <a href="javascript:$('#fileInput1').uploadifyUpload();">Upload File</a> </body> </html>
The HTML above includes an ‘input’ and ‘anchor’ element. The ‘anchor’ element is not strictly necessary as the Uploadify plugin has an configuration to automatically start the upload after a file has been selected. Here is the HTML for the sample page:
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title>Uploadify Examples</title> <link href="../../Content/UploadifyDemo.css" rel="stylesheet" type="text/css" /> <link href="../../Scripts/uploadify/uploadify.css" rel="stylesheet" type="text/css" /> <script type="text/javascript" src="<%= Url.Content("~/Scripts/jquery-1.3.2.min.js") %>"></script> <script type="text/javascript" src="<%= Url.Content("~/Scripts/uploadify/swfobject.js") %>"></script> <script type="text/javascript" src="<%= Url.Content("~/Scripts/uploadify/jquery.uploadify.v2.1.0.js") %>"></script> </head> <body> <div class="page"> <h2>ASP.NET MVC Uploadify Examples</h2> <p>The following demonstrate how to use the <a href="http://www.uploadify.com/">jQuery plugin uploadify</a> with ASP.NET MVC. The following ASP.NET MVC controller code.</p> <p> <code> public class UploadifyController : Controller<br /> {<br /> public ActionResult Index()<br /> {<br /> return View();<br /> }<br /> <br /> public string Upload(HttpPostedFileBase file)<br /> {<br /> // Process the file here.<br /> //<br /> return "Upload processed. filename=" + file.FileName;<br /> }<br /> }<br /> </code> </p> <div class="area"> <h3>Single File Upload</h3> <p>Navigate and select a file (1MB size limit) then click the 'Upload File' link.</p> <input type="file" name="fileInput1" id="fileInput1" /> <a href="javascript:$('#fileInput1').uploadifyUpload();">Upload File</a> </div> <div class="area"> <h3>Single File Upload - Auto Start</h3> <p>Navigate and select a file (1MB size limit).</p> <input type="file" name="fileInput2" id="fileInput2" /> </div> <div class="area"> <h3>Multiple File Upload - 2 Simultaneous</h3> <p>Navigate and select a three files (1MB size limit) then click the 'Upload Files' link.</p> <input type="file" name="fileInput3" id="fileInput3" /> <a href="javascript:$('#fileInput3').uploadifyUpload();">Upload File</a> </div> </div> </script> </body> </html>
This is really not much more involved a large portion of this code is HTML ‘div’ elements that are used for CSS. The sample page is then rendered as follows:
CSS
The CSS is minimal for this demo page.
/* CSS Reset ----------------------------------------------------------*/ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { margin: 0; padding: 0; border: 0; outline: 0; font-size: 100%; vertical-align: baseline; background: transparent; } h1,h2,h3,h4,h5,h6 { margin-bottom: 5px; } h1 { font-size: 2.0em; } h2 { font-size: 1.5em; } h3 { font-size: 1.2em; } h4 { font-size: 1.1em; } h5, h6 { font-size: 1em; } p { margin-bottom: 3px; } body { font-size: 14px; font-family: Verdana, Helvetica, Sans-Serif; background-color: #333; } .page { width: 750px; margin: 20px auto; background-color: #eee; padding: 20px; } .area { margin: 20px; padding: 5px; background-color: #ccc; }
This is mostly a CSS reset to normalize the differences between browsers and then a couple of rules to set how the elements render.
JavaScript
The interesting bits are in the JavaScript with this control. As mentioned earlier, the control is a jQuery plugin. Therefore you can use jQuery selectors and then call an ‘uploadify’ method to convert an HTML input (type = file) element into a flash based object. Here is the JavaScript for the demo page.
<script type="text/javascript"> $(document).ready(function() { $("#fileInput1").uploadify({ uploader: '<%= Url.Content("~/Scripts/uploadify/uploadify.swf") %>', script: '<%= Url.Action("Upload", "Uploadify") %>', fileDataName: 'file', buttonText: 'File Input 1...', multi: false, sizeLimit: 1048576, simUploadLimit: 1, cancelImg: '<%= Url.Content("~/Scripts/uploadify/cancel.png") %>', auto: false, onError: function(a, b, c, d) { if (d.status == 404) alert("Could not find upload script. Use a path relative to: " + "<?= getcwd() ?>"); else if (d.type === "HTTP") alert("error " + d.type + ": " + d.status); else if (d.type === "File Size") alert(c.name + " " + d.type + " Limit: " + Math.round(d.info / (1024 * 1024)) + "MB"); else alert("error " + d.type + ": " + d.text); }, onComplete: function(event, queueId, fileObj, response, data) { alert(response); } }); $("#fileInput2").uploadify({ uploader: '<%= Url.Content("~/Scripts/uploadify/uploadify.swf") %>', script: '<%= Url.Action("Upload", "Uploadify") %>', fileDataName: 'file', buttonText: 'File Input 2...', multi: false, sizeLimit: 1048576, simUploadLimit: 1, cancelImg: '<%= Url.Content("~/Scripts/uploadify/cancel.png") %>', auto: true, onError: function(a, b, c, d) { if (d.status == 404) alert("Could not find upload script. Use a path relative to: " + "<?= getcwd() ?>"); else if (d.type === "HTTP") alert("error " + d.type + ": " + d.status); else if (d.type === "File Size") alert(c.name + " " + d.type + " Limit: " + Math.round(d.info / (1024 * 1024)) + "MB"); else alert("error " + d.type + ": " + d.text); }, onComplete: function(event, queueId, fileObj, response, data) { alert(response); } }); $("#fileInput3").uploadify({ uploader: '<%= Url.Content("~/Scripts/uploadify/uploadify.swf") %>', script: '<%= Url.Action("Upload", "Uploadify") %>', fileDataName: 'file', buttonText: 'File Input 3...', multi: true, sizeLimit: 1048576, simUploadLimit: 2, cancelImg: '<%= Url.Content("~/Scripts/uploadify/cancel.png") %>', auto: false, onError: function(a, b, c, d) { if (d.status == 404) alert("Could not find upload script. Use a path relative to: " + "<?= getcwd() ?>"); else if (d.type === "HTTP") alert("error " + d.type + ": " + d.status); else if (d.type === "File Size") alert(c.name + " " + d.type + " Limit: " + Math.round(d.info / (1024 * 1024)) + "MB"); else alert("error " + d.type + ": " + d.text); }, onComplete: function(event, queueId, fileObj, response, data) { alert(response); } }); }); </script>
The above code uses the jQuery ready event to convert the HTML input elements as soon as possible. The demo has three HTML input elements and so most of the JavaScript above is repeated 3 times. There are many configuration options. Here are the important ones for MVC:
- uploader – This option sets where the SWF file for the flash control is located. Because this is a path, you should use one of the MVC helpers.
- script – This is the action method that is called once the file is completely uploaded to the server.
- fileDataName – This is the parameter name that is passed into the action method.
- buttonText – This sets the text in the button.
- multi – Allows the control to be configured to handle multiple files.
- sizeLimit – The maximum number of bytes for each upload.
- simUploadLimit – The number of simultaneous uploads. If you are worried about multiple files uploading and calling your action method, set this to one.
- cancelImg – The image used for the cancel icon.
- auto – Automatically starts the upload if this value is true.
- onError – Callback if there is an error.
- onComplete – Callback on the completion of every file.
Summary
There are a number of solutions for file uploads. This one is simple and has a great user experience. It does require JavaScript and Flash on the client browser.
Very nice..