A no frills AJAX uploader using ASP.NET and vanilla javascript

This is a tutorial on how to write a simple AJAX uploader. I’ve been doing more front end development at work lately, and I recently needed to write a page that processed a small file upload from the user. Because the page in question only accepted files up to 1 MB in size, I figured it would be a much better user experience to do the upload via AJAX, rather than forcing the user to sit through an entire FORM post and wait for the page to reload. Normally, I’d consider going with a third party solution, as there are quite a few AJAX uploaders available on the web. However, management wanted to reduce dependencies on third party code. This sounded reasonable to me. The files in question were going to be small, so fancy features such as progress bars that are commonly found in AJAX uploader plugins would prove to be unnecessary anyway. As a bonus, I’d get to avoid the hassle of researching all the available options out there and save time spent reading through pages of boring documentation. All in all, I was pretty happy to go through the exercise of writing my own.

The first roadblock that I encountered is the fact that Javascript can’t actually access the file system. To see why this would be a bad idea, just look at the well intentioned yet completely awful technology that is ActiveX and all the horrible malware that it has spawned. Giving a client side scripting language like Javascript access to the file system represents a gaping security hole, so it is a good thing that it cannot. To work around this limitation, we must still do a FORM post, but through the use of some clever smoke and mirrors the user never needs to leave the page.

This is accomplished using the “target” attribute of the form element. This attribute specifies where to open the page specified by the “action” attribute. For example, you can provide the value “_blank” to tell the browser to open up the “action” page in a new window. It just so happens that you can also specify an Iframe for your target attribute. So the solution will be to add a hidden IFrame element to the HTML and then specifying it as the target attribute of the form.

The HTML is straightforward. We will have a form element, a file upload element, a hidden IFrame, and a submit button. Finally, we will have a div (with the display initialized to “none”) that displays a simple “upload in progress” message along with an animated gif of a spinning wheel.

<form id="uploadForm" action="/processupload.aspx" method="post" enctype="multipart/form-data" target="upload_target" onsubmit="startUpload();"> 	  
	<input type="file" name="picFile" runat="server" size="50">                        
	<input type="submit" name="submitBtn" value="Upload">						
</form>           	     
    
<br />  
    
<div id="result" style="display:none">Upload in progress.... please wait <img src="/images/processing_small.gif" align="absmiddle" /></div>
    
<iframe id="upload_target" name="upload_target" style="width:0;height:0;border:0px solid #fff;"></iframe> 

The Javascript code is fairly simple as well. We will have two simple functions: StartUpload and StopUpload. StartUpload will simply display our hidden div:

function startUpload() {
	$('result').style.display = "block";
}

StopUpload will be called after the server has finished processing the upload. It will either display “Upload successful” or show some error message.

function stopUpload(success) {
    var result = '';
    if (success == 1) {
        $('result').innerHTML = 'The file was uploaded successfully!';
    }
    else {
        $('result').innerHTML = 'Sorry, there was an error during the file upload.';
	   }			
    }

The final piece of the puzzle is to figure out a mechanism with which to call StopUpload after the server has finished processing the upload. Because the “target” attribute is an iframe, we can write javascript code in the server response, which will then automatically be called when the browser renders the result in the IFrame.

The following is a bare bones Page_Load() function for the processUpload.aspx specified in the form action. Obviously, a real world version would contain more robust error handling, security checks, business logic, and so on. It’d also have a more descriptive file name as well.


protected void Page_Load(object sender, EventArgs e)
{
    int success = 0;
    try
    {
	HttpPostedFile uploadedFile = Request.Files[0];

        //In the real world we'd want to pull set the upload path from web.config or something along those lines
        string imageUploadPath = "C:\\temp";  
	uploadedFile.SaveAs(imageUploadPath); 

        string iframeJavascript = "<script language="javascript" type="text/javascript" >window.top.window.stopUpload(1)</script>";
 
	Response.Write(iframeJavascript);  
    }
    catch (Exception e)
    {
        //here is where we could send back more detailed error information to the browser...
        string errorResponse= "<script language="javascript" type="text/javascript" >window.top.window.stopUpload(0)</script>"; 
	Response.Write(errorResponse);      
    }
}

Lo and behold, we now have a fully functional AJAX uploader. From here we can make any number of improvements to make it more useful. For example, if we wanted StopUpload to display a more useful error message, we could add an “ErrorMessage” parameter to the javascript function, and have the server write out appropiate messages based on the nature of the error: “File size too large”, “Error processing file”, and so on. Of course, if you find yourself spending too much time implementing, testing, and debugging additional functionality, it would make more sense to use the many AJAX uploader plugins already out there on the internet (many of them free).

Leave a Reply

Your email address will not be published. Required fields are marked *