Search This Blog

Wednesday, February 26, 2014

Ajax FileUpload on all Browsers including IE 8, 10

File Upload in ASP.NET MVC via ajax

Problem

While looking for fileupload options via ajax and without posting the whole form, we often come across code in the internet using FormData API, which works perfectly fine on chrome and mozilla but on on IE. so a code snippet using a FormData API would like this below

//View Code
<script type="text/javascript">
    function save() {
        $("#test").submit();
    }
    function submitForm() {
        var formData = new FormData($('#test')[0]);

            $.ajax({
                url: '@Url.Action("Upload","FileUpload")',
                type: 'POST',
                data: formData,
                async: false,
                success: function (data) {
                    alert('posted')
                },
                cache: false,
                contentType: false,
                processData: false
            });

            return false;
    }
</script>
<h2>Index</h2>
<input type="button" value="Submit" onclick="save();" />
    
<form id="test" action="javascript:submitForm();" method="post" enctype = "multipart/form-data">
    <div>
        <label for="fileUpload">File upload</label>
        <input type="file" id="fileUpload" name="fileUpload" />
    </div>
</form>

//Controller Code
public ActionResult Upload()
        {
            HttpPostedFileBase postedFile = Request.Files[0];
            return View();
        }
The above snipped works fine on chrome and mozilla and you will be able to see the postedFile in the controller but it does not work on IE because most versions of IE does not support FormData.

Solution

So the solution I came up with after going some recommendations over internet about HTML controls on different browsers is that its better to use iframes. So Idea is to point the target of the form to an iframe and even bind a load event to the iframe so that you know when the upload is finished and write additional jquery functions. Also you can even hide the iframe and not show the user. But this solution works on IE as well. The code is as below

The code also shows how to post additional data along with the file post.

@{
    ViewBag.Title = "Index";
}
<script src="~/scripts/jquery-1.9.1.min_.js"></script>
<script type="text/javascript">
    function successFunction() {
        alert($('#my_iframe').contents().find('p').html());
    }
    function redirect() {
        //debugger;
        document.getElementById('my_form').target = 'my_iframe'; //'my_iframe' is the name of the iframe
        //document.getElementById('my_form').submit();
        var callback = function () {
            if (successFunction)
                successFunction();
            $('#my_iframe').unbind('load', callback);
        };

        $('#my_iframe').bind('load', callback);
        $('#hfParam').val('id:1');

        $('#my_form').submit();
        //$("#my_form").trigger("submit");
     
    }
</script>
<h2>Index</h2>
<input type="button" name="action" value="Upload" onclick="redirect();"/>
<form id="my_form" name="my_form" action="/FileUpload/UploadFile" method="POST" enctype="multipart/form-data" >
    <div id="main">
        <input name="my_hidden" id="hfParam" type="hidden" />
        <input name="my_files" id="my_file" type="file" />
        <iframe id='my_iframe' name='my_iframe' src="">
        </iframe>
        <div id="someDiv"></div>
    </div>

</form>


[HttpPost]

        public ActionResult UploadFile()

        {
            ContentResult result = new ContentResult() { Content = "<p></p>", ContentType = "text/html"};
            HttpPostedFileBase postedFile = Request.Files[0];
            try
            {
                result.Content = "<p>" + postedFile.FileName + "</p>";

            }
            catch (System.Exception ex)
            {
                result.Content = ex.Message;
            }
            return result;
        }

24 comments:

  1. Thanks for this post!

    This is exactly what I needed. Unfortunately, I need to support IE8+ as well as the more modern browsers. This did the trick without having to use a plugin.

    ReplyDelete
    Replies
    1. It's good to know that it was of help to you.

      Delete
  2. It should work in IE9, not the example with FormData but the work around. Please note that if you are posting JSON by using JSON.stringfy() method then you will need to Json2.js script as IE does not support the method.

    ReplyDelete
  3. Thank you so much! I've been banging my head against the wall trying to get other solutions to work. The organization I work for requires compatibility with IE8. Your solution was the only one that worked for me.

    ReplyDelete
    Replies
    1. Good to know, thanks for your feedback. I try to post on stuff, that I myself have faced issues solving, I hope it helps more and more people.

      Delete
  4. This looks promising (have to try it out but looks like it will work). Most of the sites I encountered in my search used HTML5 features which do not help me considering I have to support a website on older IE versions.
    Thank you for your post.

    ReplyDelete
  5. I'm having trouble in IE8. I have to click the Upload button 3 times to get the form to submit. Have you run into this?

    ReplyDelete
    Replies
    1. Sorry Anon I did not run into any such issues. Either it will work or it will not. You can try updating to the latest stable version of jquery that you might be using.

      Delete
  6. Dear KAUSHIK,

    Can you share the project? I am new to JQuery & MVC.

    ReplyDelete
  7. Dear abdul, I do not have a project as such specifically created for this, but I will try and see if I can post something on github. I have never used github, but I believe sharing is possible through that. Sorry I did not reply earlier as I was down with fever.

    ReplyDelete
  8. Dear KAUSHIK,
    Thanks for consideration. Get Well Soon.

    ReplyDelete
  9. This comment has been removed by the author.

    ReplyDelete
  10. Dear KAUSHIK,
    Thanks a lot. As good as it gets. btw there may be wrong id of frame for unbind in code snippet.

    ReplyDelete
    Replies
    1. Thanks for the correction, I have updated the post. Appreciate it

      Delete
  11. Hello KAUSHIK, the example works in cross domain?

    ReplyDelete
    Replies
    1. Should work if the browser allows it otherwise you will have to use some kind of proxy on your present domain and route that from the server side.

      Delete
  12. Hi Kaushik,

    Thanks for the nice example. It does work on the controller side for me in I.E 9.0 but two issues.

    1) It wont come back into the javascript post controller processing. I need to close a dialog and run some jquery function on the success of form posting.

    if (successFunction) -- Doesnt fire (also where is this boolean var)

    2) I.E open another tab on form submit, is this avoidable

    thanks.
    appreciate any help.

    Manish Jadhav

    ReplyDelete
    Replies
    1. manish,
      In the example if you closely notice, it actually does not post back the form but the iframe is made the target, so it will post back the iframe so the page will not reload. See the line below

      document.getElementById('my_form').target = 'my_iframe';

      I hope this clarifies.

      Delete
  13. javascript runtime error access is denied error occured
    while uploading file IE 9

    ReplyDelete
    Replies
    1. code from KAUSHIK GHOSH is not checking for error codes, even if 400 Bad Request is returned by server, 'successFunction' will be invoked. In case error is returned by server and size is less than 512 bytes, then you have troubles with IE for accessing the iframe content (see https://blogs.msdn.microsoft.com/ieinternals/2010/08/18/friendly-http-error-pages/ )

      Delete
  14. please help me to resolve above error

    ReplyDelete
    Replies
    1. Make sure your controller action is accepting post properly and also the file that you are trying to upload is accessible.

      Delete