RSS

ASP.NET Ajax file upload using jQuery File Upload plugin

11 Sep

Async Ajax file upload sounded like “science fiction” to me up until some time ago. I remember those days, back in Classic ASP, when I had to employ 3rd party components to have the browser upload files. When ASP.NET introduced FileUpload control, I was truly excited. It was plain easy to use. However, it still required a full postback. Several months ago I saw that AjaxControlToolkit provided an AsyncFileUpload control, and I think that this was the first time I’ve heard of the idea to provide async file upload. However, a quick test I performed back then failed, and I decided to forgo the idea till bugs are fixed and things become more stable. I even developed a File Upload control in Silverlight which provided me with an async upload (as well as other features I needed back then). Basically I continued to use ASP.NET’s excellent FileUpload where possible, up until today, as I had a situation in which I preferred to check on async upload solutions again.

So, a quick search in Google led me to check out this jQuery File Uploader. It looked good, looked like it was working ok, and there was a sample code in C# (WebForms) which got me going quickly (MVC sample is also available). One last thing: although it seems to have jQuery UI support for the “look and feel”, I wanted the most basic functionality of uploading a file asynchronously as I had to reuse graphics from the existing project.

The sample code taught me that html now allows multiple file selection. This was new to me. I tried to track this down and found out the the “multiple” attribute is still in draft, but is already working in some of the newer browsers (unfortunately, IE9 does not seem to support it).

Core ajax upload

In order to get things going, you’ll need the following (stated also in the requirements page):

  1. jQuery 1.6 or above.
  2. jQuery UI 1.8 or above (widget factory is the minimum requirement).
  3. jQuery File Upload plugin. For the most basic implementation, you’ll only need the files jquery.fileupload.js and jquery.iframe-transport.js from that zip.

I based the following code on the “Basic Plugin” instructions. Here’s the client code:

  1. Lines 9-12 are the basic scripts required. I noticed that without the iframe-transport js file, IE doen’t upload anything. As for the jQuery and jQuery UI, you may choose to use the available CDN’s, such as Google Libraries API or Microsoft Ajax Content Delivery Network.
  2. Line 15 activates the fileupload plugin.
  3. Line 16 seems to be required in IE9 for repeated uploads. The documentation states that “By default, the file input field is replaced with a clone after each input field change event. This is required for iframe transport queues and allows change events to be fired for the same file selection, but can be disabled by setting this option to false.” On my machine IE9 failed to upload after the first attempt, unless I set this flag to false. UPDATE: On another website I’m developing, setting this flag to true or false made no difference and IE failed repeated uploads. I’m not sure why, but I just guess that there was some coincidental conflicts between this mechanism and the website’s that caused this to malfunction. What I ended up doing was replacing the file field with jQuery, each time the ‘done’ callback was called, and activated the plugin on the new file field.
  4. Line 17 states that the result is expected on json format.
  5. Line 18 sets the upload url.
  6. Lines 19-23 handle the result using the ‘done’ callback (as shown in the File Upload “basic plugin” page.
  7. Line 28 defines the html file upload with the multiple attribute (“multiple” is not required for running this sample).

The server side implementation is a standard ashx. I based it on Bo Schatzberg’s sample:

  1. Line 10 checks if there are files being uploaded. I wasn’t familiar with the context.Request.Files collection before, so thanks Bo! You may want to log and return a message if there are no files.
  2. Lines 12-14 establish a target location for the uploaded files.
  3. Line 16 gets the file. You may ask yourself why this implementation doesn’t iterate over the context.Request.Files collection to get all the files (after all, we did ask for multiple file selection and uploads). It did, originally, but then I noticed that although the files are multiply selected, they are uploaded one at a time.
  4. Lines 17-18 determine the full file name and perform the actual save.
  5. Lines 20-23 render a json response to the client. Note that line 20 contains a content type of “text/plain” instead of the anticipated “application/json”. As the FAQ states, IE displays a download dialog if the content type is “application/json” as it originally should have been. I didn’t notice this on IE9, but perhaps in an earlier IE this is the case.

Note that the ‘file’ reference in line 16 references a Stream, so you don’t necessarily have to save the file before processing it. You can just use a StreamReader or the like and process the data (thus you can remove lines 12-18 completely if you choose to do so).

There are some other Options you can tweak detailed on this page. More importantly, the options page also documents many callback events which can be used. For example, if you’d like to intercept when a file is selected, you may want to override the default implementation of the ‘add’ operation. As the documentation states, ‘add’ defaults to submitting the data using ‘data.submit( )’. But you might want to perform a validation on the selected file, for example, that the file extension is correct. So your implementation may look like this:

Although the documentation states that it’s possible to block the file selection type using “accept=’image/png’ “, I preferred to test it myself and to provide a validator-like error message. Note that this example also addresses an actual issue I came across: when I tried to use the good old validators on the file element as I always did (for example when a file selection is mandatory, or to test the file extension), they did not work as expected. It’s as if the ‘onchange event life-cycle’ was faulty when it came to the ‘add’ callback. That’s why I reverted to a Label and to checking the file extension “manually” as shown above. Another alternative may be to instruct the upload plug-in not to start uploading the files immediately, and to validate when the user manually clicks on a certain “upload” button.

Form Data

One other feature I found to be useful, is the ability to upload not only the file, but also plain data, either form element values (which is the default), or just custom data. Consider the options to upload with the file user related data, or just plain context data. I used to do this using the query string, but now this can be easily done using the ‘formData’ callback. Here’s the client code:

Here’s the server side code change:

Uploaded file size limitations

Last but not least, in ASP.NET the upload max default is 4096K, which means that you are limited in file upload size. You can change that easily in the web.config using the maxRequestLength:

If you have no control over this, you may want to check the maxChunkSize plugin option, which should be able to upload your files in chunks.

Summary

No doubt that file uploading in the web has come a long way since the days of Classic ASP and even ASP.NET’s FileUpload control. Thumbs up for Sebastian Tschan on his excellent File Upload plugin which seems to provide lots and lots of features (most of which weren’t discussed in this post at all, but are detailed here, such as resume upload and cancel upload).

 
47 Comments

Posted by on 11/09/2011 in Software Development

 

Tags: , , ,

47 responses to “ASP.NET Ajax file upload using jQuery File Upload plugin

  1. josematta

    29/10/2011 at 00:57

    Does this works for IE8 and IE7? I mean the jQuery library

     
  2. Nobuyuki

    12/11/2011 at 19:14

    Thank you for posting a good article.
    I hope you can help me? How can I start uploading by submit button on click? Many thanks.

     
    • evolpin

      12/11/2011 at 21:51

      Hi Nobuyuki,

      I’m no expert on the subject, but I did manage to come up with something. For some reason the fileupload plugin website does not contain enough information about this.

      My solution is quite simple and relies on the API’s programmatic abilities stated under “Programmatic file upload”:
      1. I added 2 file elements within in a div with an id of ‘files’. These would serve for file selection (instead of the main ‘fileupload’, which would be hidden).
      2. I then invoked ‘add’ programmatically as stated in the docs. Assuming you have a regular button with an id of ‘btnGo’, the following does the trick:

      $(‘#btnGo’).click(function () {
      var inputs = $(‘#files input’); // get all the input type=’file’ fields within the ‘files’ div.
      var arr = $.makeArray(inputs); // turn the jQuery objects into an array
      var filesList = $.map(arr, function (element, index) { // iterate over the array and create an array of File objects
      return element.files[0]; // assume that the file element has only a single file selected
      });

      $(‘#fileupload’).fileupload(‘add’, { files: filesList }); // upload by calling ‘add’
      });

      Unfortunately, this seems to work on FF but not on IE. The API states that for “Programmatic file uploads for browsers without support for XHR file uploads” you can specify a fileInput argument with the list of jQuery input:file, but this didn’t work.
      So I tried a different and uglier approach which seemed to work in IE:

      1. define an obj variable prior to calling ‘fileupload’
      2. add an ‘add’ function to the fileupload options like so:
      add: function (e, data) {
      obj = data;
      }, // rest of the options
      3. upon clicking your btnGo button, call obj.submit() like so:
      $(‘#btnGo’).click(function () {
      obj.submit();
      });

      You see, adding an ‘add’ callback causes fileupload not to start uploading immediately, till you call submit on the data object.
      This seems to be working both on IE and on FF. Ugly, but it works.

      Hope this helps.

       
  3. Nobuyuki

    12/11/2011 at 23:42

    Hi Evolpin

    Thank you for your response and your time.
    You have put me into the right direction. I have defined an object and stored the data for late submission and it worked with FF, but no joy with IE yet.

    Thank you for your help.

    Regards,

     
    • evolpin

      13/11/2011 at 13:58

      Is IE working for you in automatic mode at all, or is it just at “queuing mode” not working?
      If not, I’d suggest focusing on that problem first. Check that you include the transport js file.
      If only in queuing mode, what exactly is the problem?

       
  4. Ong

    11/01/2012 at 09:16

    Its working on all browser except IE 9. How do we solve this problem? Firebug nor fiddle shown no errors….

     
    • evolpin

      12/01/2012 at 07:29

      Actually this *is* working on IE9, so it’s possible that you have missed a step, or discovered a bug. Make sure that you include *all* the references to the required JS files; read the comments in the post with regards to IE9 and also try to read the FAQ in the FileUpload web site: https://github.com/blueimp/jQuery-File-Upload/wiki/Frequently-Asked-Questions. I hope you’ll be able to get this to work.

      If not, please open a new website and retry as explained above. Assuming you get it to work, I hope that you’ll be able to tell the difference between the websites and why it wasn’t working at first.

       
  5. NickP

    29/02/2012 at 16:00

    Evolpin, thanks for a great solution to a common ASP.Net/AJAX challenge. This is the only tutorial that really solves the problem without using tricky hacks.

    I do have a problem, however. I got your solution to work perfectly when debugging in Visual Studio. But when I run it on my web server (using IIS), I get a “parsererror” response. I used JSONLint to test my serialized JSON response string I copied from debugging in VS. JSONLint validation failed because of the C# escape character in front of my double quotes \”. I tried using NewtonSoft’s JSON.Net to serialize the string, but it gives the same result because C# really just adds the escape character when viewing debugging output. So this leads me to believe that this is not the problem.

    Do you have any ideas why this may be happening on the web server but not in my VS debugging environment?

     
    • evolpin

      29/02/2012 at 19:42

      Hi NickP,

      I can’t really tell from the given information what the problem is. You may want to try running on a different IIS just to ensure that there isn’t a particular issue with the one you’re running on. If the quote characters are something that you are rendering on purpose, you might want to html encode them or replace them with a different character, depending on your needs.

       
      • NickP

        29/02/2012 at 21:14

        Actually, I have discovered what causes the bad JSON. My AjaxFileHandler is throwing a file-not-found exception on the server and trying to pass that back as the JSON resonse, which then fails parsing.

        The file-not-found error is more perplexing, however, because file.FileName points to the file on my local machine where I am selecting it from. Shouldn’t the posted file be agnostic of its origin location?

         
      • evolpin

        29/02/2012 at 22:13

        When you write that

        file.FileName points to the file on my local machine

        You mean that you have the file name and path? If so, then I’d say something isn’t implemented correctly. I’d say that it probably explains why the IIS “isn’t working well”: Assuming that the IIS is on a remote server that you’re browsing to, the IIS attempts to reach a file on your local path. But then again, it’s wrong to have your original path in the first place uploaded.

        I have sent you the sample code for this – I hope it’ll help you.

         
  6. NickP

    29/02/2012 at 22:25

    Thanks for your help. I got past the file issue. Not to keep you engaged in my problem, but any idea why data.result might return [Object object] instead a valid JSON string? This started happening on both my dev machine and server. The handler is writing the correct response using context.Response.Write(serializer.Serialize(result));. When I apply JSON.stringify, I get this: {“0″:{},”length”:1,”prevObject”:{“0″:{“jQuery16202453099300957165″:43},”length”:1},”selector”:”.contents()”}.

     
  7. NickP

    29/02/2012 at 22:29

    Fixed it… I was using contentType: “json” instead of dataType: “json”. Thanks for your help!!! Once again, fantastic job on this!

     
  8. CurtisLGray

    13/04/2012 at 18:31

    FYI… I was having the same exact problem as Ong. After adding a bunch of “alerts” to see what was being passed around, and based on what “evolpin” stated, I found that in IE the full path of the file (e.g. C:\User\Pictures\MyPict.jpg) was being used. While in FF and Chrome, only the file name was used. My quick fix was to modify the .ASHX file like so:

    var file = context.Request.Files[0];
    string newFileName = Path.GetFileName(file.FileName);
    string filename = Path.Combine (path, newFileName);

    Hopefully this helps the next guy…

     
  9. imranbluffy

    23/04/2012 at 09:19

    IF i upload one invalid file it gives proper validation message. that invalid file format, if i choose again the same file it doesnot give error. i want the solution its only with IE

     
  10. Azhar

    25/04/2012 at 14:40

    How can we make file mandatory to upload

     
    • evolpin

      26/04/2012 at 20:20

      Please read the section in the article which covers using the ‘add’ operation. The examples shows how to use a regexp to validate the file type – you can replace it with any validation adequate to your needs.

       
  11. mythili p

    18/05/2012 at 07:26

    Great post.. does it work on mobile browsers also?? can u pls let me know? thanks in advance!

     
    • evolpin

      18/05/2012 at 15:25

      I really don’t know. You’ll have to post a question to the author of the plugin.

       
      • ra1

        20/07/2012 at 10:48

        hi send me working sample code to my id please

         
  12. ra1

    20/07/2012 at 10:22

    Hi ,code is not working for me.in javascript add: function (e, data) {…here code is not going inside,please help me

     
  13. svc

    21/07/2012 at 08:34

    Hi your plugin,when i integrated to my project means,it is conflicting with other js files,what i need to do please reply

     
    • evolpin

      21/07/2012 at 21:13

      It’s not my plugin, and I really can’t tell what conflict you have from your email.

       
  14. ra1

    23/07/2012 at 17:19

    Thanks a lot for sending code

     
  15. ra1

    23/07/2012 at 17:20

    Hi can i call webservic method in javascript after file handler work got over? and progress bar ,please reply and ur plugin is grt,helpd me lot thanks

     
  16. Bram

    17/10/2012 at 10:53

    I’m having this very strange problem where directly after the upload completes, the following error is returned in my browser console:
    POST http://uploadvideo.site.com/AjaxFileHandler.ashx 404 (Not Found)

    Now the strange thing is that everything goes fine when uploading files smaller than about 25Mb or when testing with bigger files through debugging in visual studio. On our IIS server big files return the error.

    I have changed the httpRuntime settings in my web.config so that shouldn’t be the problem

    Anyone an idea?

     
    • evolpin

      17/10/2012 at 23:41

      Assuming that indeed you tried to tweak the maxRequestLength, try to configure the following:

      <system.webServer>
      <security>
      <requestFiltering>
      <requestLimits maxAllowedContentLength="500000000" />
      </requestFiltering>
      </security>
      </system.webServer>

       
      • Bram

        18/10/2012 at 09:11

        That solved it. Amazing, thanks!

         
      • Monodeep Bhattacharjee

        25/11/2012 at 20:12

        Can you please mail me the code??

         
  17. Monodeep Bhattacharjee

    25/11/2012 at 20:12

    @evolpin Can you please mail me the code??

     
  18. James

    12/02/2013 at 09:53

    Any way to get a copy of the code ? screen shots of code is so 1999

     
  19. ryan paul

    26/02/2013 at 11:41

    How can i add a parameter to include a text to receive by the generic handler.
    Let us say i want to include a json to send to the server and the data that been sent will serve as the new filename of the upload file, in short i will change the filename of the uploaded file

     
    • evolpin

      27/02/2013 at 08:16

      Please review the example that sends form data.

       
  20. samar chougule

    27/03/2013 at 10:08

    Really this good article ,it help me lot of ,but can you please tell me how can show uploaded image on page ,i want to do this by setting httphandler response as image i can do it ?or any other way to achive same ,now returning image path and preserve this path in hidden field simultaneously i want to return image to show on page.please can suggest better way to do this

     
    • evolpin

      29/03/2013 at 20:59

      not sure what the problem is. once the file is uploaded, simply set the img url to either the direct image location on the server or to an http handler that will return it.

       
  21. luca

    26/05/2013 at 22:13

    hallo,
    interesting article…
    is it possible to have a copy of the code?
    Thanks in advance

     
  22. svizi

    04/06/2013 at 15:54

    Hi,

    thanks for sharing this knowledge.
    I have tried to implement your first example ( simply an input form) but when i pick the file i want to upload the webpage doesn’t do anything.
    As i read the time you browse and select the file it gets uploaded.

    Any hints on what may be wrong?

     
  23. ar

    25/06/2013 at 23:01

    I’m having a series of small problems implementing your examples (to see if they’re applicable to what I’d like to do) – do you happen to have a zip file containing those examples? Thank you.

     
  24. meenie

    01/07/2013 at 11:04

    Very nice indeed like the article…! I need an understandable way of creating a file upload script…!

     
  25. plonder

    09/08/2013 at 11:08

    Hi! I tried to implement your article, but I couldn’t get it working. Could you send to me a zip with your solution? Thanks

     
  26. luca

    23/08/2013 at 11:02

    I’m interested too in a zip of the solution; could you put it for download? thanx

     
  27. mohit

    20/09/2013 at 13:11

    thank you Evolpin for such a great contribution. How systematically you described each things so that a beginner can easily learn . You inspired me to post some blogs that would be useful as this for others.
    thank you.

     
  28. Denis

    04/01/2014 at 17:57

    Hey, evolpin. Thank you for this article. It actually helped me :)

    I have a question about posting additional data with file. Lines 10, 11 on your screenshot http://evolpin.files.wordpress.com/2011/08/form2.png?w=645 How to tell with which file data1 and data2 are related? I mean, is data1 relates strictly to File[0] ?

     

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 60 other followers

%d bloggers like this: