1

Im using ASP.NET MVC5. My goal was to upload file using jQuery ajax. When successful, return a partial view of the uploaded files in a table. When I step through the jQuery code, the id and files are correct, but when stepped into Action, both parameters are null. Here are my codes:

Controller's Action:

[HttpPost]
        public ActionResult AddAttachments(string id, IEnumerable< HttpPostedFileBase> files)
        {            
            if (files != null)
            {
                //save files
            }
            var cardKey = db.CardKeys.Single(s => s.CardKeyID == Convert.ToInt32(id));
            var attachments = cardKey.Request.Attachments;
            return PartialView("_AttachmentsTable",attachments);
        }

jQuery:

$(function () {
    var table = $("#attachmentTable").DataTable();
    var path = MySettings.addAttachmentURL;
    $("#btnAddAttachment").click(function (event) {
        event.preventDefault();

        var formData = new FormData();
        var cardKeyID = $("#CardKeyID").val();

        var formData = $.each($("#files")[0].files, function (i, file) {
            formData.append('file-' + i, file);
        });
        console.log("formData = " + formData);
        $.ajax({
            type: "POST",
            url: path,
            contentType: false,
            processData:false,
            cache:false,
            data: {id:cardKeyID,files: formData },
            success: function (partialResult) {
                $("#tableData").html(partialResult);
                table = $("#attachmentTable").DataTable();
            },
            error: function (jqXHR, textStatus, errorThrown) {
                $("#message").html(JSON.stringify(jqXHR).toString());
                alert("AJAX error: " + textStatus + ' : ' + errorThrown);
            }
        });
    });
});

Razor View:

<fieldset>
            <legend>Add Attachments</legend>
        <div class="row">
            <div class="col-md-4">
                <div class="form-group">
                    @Html.Label("File Upload", new { @class = "control-label col-md-6" })
                    <div class="col-md-6">
                        <input type="file" id="files" name="files" multiple/><br />
                        <input type="submit" id="btnAddAttachment" value="Add Attachment"/>

                    </div>
                </div>
            </div>
            <div class="col-md-4">
                <div class="form-group">
                    @Html.Label("File Description", new { @class = "control-label col-md-6" })
                    <div class="col-md-6">
                        @Html.TextBox("FileDescription")
                    </div>
                </div>
            </div>
            <div class="col-md-4">
                <div class="form-group">
                    @Html.Label("Comment", new { @class = "control-label col-md-6" })
                    <div class="col-md-6">
                        @Html.TextBox("Comment")
                    </div>
                </div>
            </div>
        </div>
        <div id="tableData">
            @Html.Partial("_AttachmentsTable",Model.Request.Attachments)
        </div>
        </fieldset>
5
  • You can't use the ModelBinder to retrieve uploaded files, you need to use Request.Files. See the question I marked as duplicate for more information. Commented Feb 10, 2016 at 15:45
  • I checked Request object in debugging mode and Files property was empty. Commented Feb 10, 2016 at 15:47
  • In which case, refer to the working jQuery example in the duplicate question for working code. Commented Feb 10, 2016 at 15:48
  • I have tried those jQuery code, jQuery data is ok, but when pass ajax data into MVC action, parameters are all null. That's my problem. Commented Feb 10, 2016 at 15:51
  • Ok, the duplicate I marked does have working code, but doesn't directly address your issues. I added an answer for you. Commented Feb 10, 2016 at 15:57

1 Answer 1

1

The issue is because you need to provide FormData directly to the data property of $.ajax, not within an object as it will be encoded. If you need to add data to the request, append it to the FormData object:

var formData = new FormData();
var cardKeyID = $("#CardKeyID").val();
var formData = $.each($("#files")[0].files, function (i, file) {
    formData.append('file-' + i, file);
});
formData.append('id', cardKeyID);

$.ajax({
    data: formData,
    // other properties here...
});

Then in the controller you need to retrieve the data directly from the Request:

[HttpPost]
public ActionResult AddAttachments()
{    
    var id = Request.Params["id"];
    foreach(var file in Request.Files) {
        //save files
    }

    var cardKey = db.CardKeys.Single(s => s.CardKeyID == Convert.ToInt32(id));
    var attachments = cardKey.Request.Attachments;
    return PartialView("_AttachmentsTable",attachments);
}

Note that if the form element contains all fields that you want to send in the request, you can avoid the $.each and having to append directly and simply use:

var formData = new FormData($('form')[0]);
Sign up to request clarification or add additional context in comments.

2 Comments

Hi Rory, var formData = new FormData($('form')[0]); does work. But when I use the example the code formData.append('id', cardKeyID); javascript complained: 0x800a01b6 - JavaScript runtime error: Object doesn't support property or method 'append'. That's very strange.
That's odd. Which browser are you using?

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.