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();
            }
        }

    }
3
  • 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. Commented Feb 23, 2012 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... Commented Feb 24, 2012 at 9:38
  • oh yes, this has very much to do with your problem. See my answer. Commented Feb 24, 2012 at 9:58

2 Answers 2

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
    }
});
Sign up to request clarification or add additional context in comments.

4 Comments

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?
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..
This is what did the trick....i then had to parse my JSON result, but it worked..thanks
@user1202717, then maybe you might consider accepting my answer unless of course you have further questions?
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");
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.