4

When I try and upload a file using ASP.NET MVC it works fine in FF && Chrome, but in IE and Opera a dialog pops-up which asks me to either download, save or cancel.

Choosing either of the options, prevents the fileupload from working. How can I get round this problem?

 public class ImportModel
    {                     
        [Required]
        [FileExtensions("csv", ErrorMessage = "Please upload a valid .csv file")]
        public HttpPostedFileBase File { get; set; }
    }



[HttpPost]
    public virtual ActionResult StartImport(ImportModel model = null)
    {
        if (model != null)
        {
            var status = _importService.StartImport(model);
            return Json(status, JsonRequestBehavior.AllowGet);
        }
        return null;
    }

View code below (summarised):

<div id="dlgImport" class="hidden">

        @using (Html.BeginForm(MVC.Import.StartImport(), FormMethod.Post, new { @class = "smallForm", id = "frmImport", enctype = "multipart/form-data" }))
        {            
            <div class="fields-inline">
                <div class="editor-label">
                    @Html.Label("File")
                </div>
                <div class="editor-field">
                    @Html.TextBoxFor(x => x.File, new { @class="input-file", type = "file" })
                    @Html.ValidationMessageFor(x => x.File)
                </div>              
            </div>
        }
    </div>

</div>



$(function() {
        $("#frmImport").ajaxForm({
            success: function (responseHtml) {
                // response is wrapped in pre tags by the browser - the ajax upload is carried out using an iframe                                                
                var response = $.parseJSON($(responseHtml).text());
            }
        });
});


 var vm = {

        startImport: function () {

            if ($("#frmImport").valid()) {                
                $("#frmImport").submit();
            }
        }

    }
jaffa
  • 26,770
  • 50
  • 178
  • 289
  • You probably have an error in the way you are calling this action. Any chance to see your view code? And your javascript? Maybe you are using some client side file upload component (since you use Ajax)? Is this component compatible with IE? Also returning null from a controller action is never a good idea. If the client code expects the response to be in some specific format (like JSON for example) returning null would definitely break it. – Darin Dimitrov Feb 23 '12 at 17:26
  • Hi Darin, I've added view code. I'm using Jquery's ajaxForm. Not sure if this has anything to do with it... – jaffa Feb 24 '12 at 09:38
  • oh yes, this has very much to do with your problem. See my answer. – Darin Dimitrov Feb 24 '12 at 09:58

2 Answers2

13

Now that you have posted your code it looks like that you are using the jquery form plugin. As explained in the documentation this plugin supports file uploads using AJAX but you cannot return JSON from your server side script:

Since it is not possible to upload files using the browser's XMLHttpRequest object, the Form Plugin uses a hidden iframe element to help with the task. This is a common technique, but it has inherent limitations. The iframe element is used as the target of the form's submit operation which means that the server response is written to the iframe. This is fine if the response type is HTML or XML, but doesn't work as well if the response type is script or JSON, both of which often contain characters that need to be repesented using entity references when found in HTML markup.

To account for the challenges of script and JSON responses, the Form Plugin allows these responses to be embedded in a textarea element and it is recommended that you do so for these response types when used in conjuction with file uploads. Please note, however, that if there is no file input in the form then the request uses normal XHR to submit the form (not an iframe). This puts the burden on your server code to know when to use a textarea and when not to.

So basically your upload controller action should respond with:

<textarea>{"foo":"bar"}</textarea>

instead of:

{"foo":"bar"}

Also you should not use the application/json response content type in this case.

You could write a custom action result to achieve that:

public class FileJsonResult : JsonResult
{
    public FileJsonResult(object data)
        : base()
    {
        Data = data;
        JsonRequestBehavior = JsonRequestBehavior.AllowGet;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        context.HttpContext.Response.Write("<textarea>");
        base.ExecuteResult(context);
        context.HttpContext.Response.Write("</textarea>");
        context.HttpContext.Response.ContentType = "text/html";
    }
}

and then:

[HttpPost]
public virtual ActionResult StartImport(ImportModel model = null)
{
    if (model != null)
    {
        var status = _importService.StartImport(model);
        return new FileJsonResult(status);
    }
    new FileJsonResult(new { status = false, errorMessage = "The model was null" });
}

Now you might also need to adapt your success handler to strip the <textarea> tags:

$('#frmImport').ajaxForm({
    success: function (responseHtml) {
        var responseHtml = responseHtml
            .replace(/\<textarea\>/i, '')
            .replace(/\<\/textarea\>/i, '');
        var response = $.parseJSON(responseHtml);
        // do something with the response
    }
});
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Thanks for the advice. I'll give it a try. Do you know why my code works in FF & Chrome though? Why is IE a problem? – jaffa Feb 24 '12 at 13:35
  • I suppose Firefox and Chrome treat the JSON response as text, and show it inside the IFRAME. This is not a nice way to do it because it will typically be parsed and put inside a simple HTML document, and some characters might be turned into HTML entities if read back through the DOM.. – hallvors Feb 28 '12 at 09:16
  • This is what did the trick....i then had to parse my JSON result, but it worked..thanks – BoundForGlory Jun 29 '12 at 18:40
  • @user1202717, then maybe you might consider accepting [my answer](http://stackoverflow.com/questions/11266183/ie-wants-to-download-json-result-mvc3/11266355#11266355) unless of course you have further questions? – Darin Dimitrov Jun 29 '12 at 18:53
0

I had the same problem with IE8 and this answer helped me a lot. But I needed to make some changes that worked very well in IE8, Chrome and Firefox.

Follow changes below:

success: function (responseText) {
    try{
        var response = $.parseJSON(responseText);
        //code ...
    }    
    catch(ex) {
        //error code
    }
}

[HttpPost]
public JsonResult Upload(HttpPostedFileBase file) {
    //code
    return Json(new { Success = "true", Message = "Done!" }, "text/html");
}
julienc
  • 19,087
  • 17
  • 82
  • 82
Diego Cotini
  • 1,039
  • 2
  • 18
  • 25