3

I have an ASP.NET MVC 5 application. And I'm trying to send a POST request with the Model data, and also include user selected files. Here is my ViewModel (simplified for clarity):

public class Model
{
    public string Text { get; set; }
    public long Id { get; set; }
}

Here is the controller Action:

[HttpPost]
public ActionResult UploadFile(long userId, Model model)
{
    foreach (string file in Request.Files)
    {
        // process files
    }

    return View("Index");
}

Html input element:

<div>
    <input type="file" name="UploadFile" id="txtUploadFile" />
</div>

And the JavaScript code:

$('#txtUploadFile').on('change', function (e) {
    var data = new FormData();
    for (var x = 0; x < files.length; x++) {
        data.append("file" + x, files[x]);
    }
    data.append("userId", 1);
    data.append("model", JSON.stringify({ Text: 'test text', Id: 3 }));

    $.ajax({
        type: "POST",
        url: '/Home/UploadFile',
        contentType: false,
        processData: false,
        data: data,
        success: function (result) { },
        error: function (xhr, status, p3, p4) { }
    });
});

The problem is that when the Request reaches controller action, I have files and 'userId' populated, but 'model' parameter is always null. Am I doing something wrong when populating FormData object?

Igor Goroshko
  • 255
  • 4
  • 14
  • 1
    With contentType: "application/json" it will not send files. – Igor Goroshko Sep 26 '15 at 22:14
  • 1
    Refer [this answer](http://stackoverflow.com/questions/29293637/how-to-append-whole-set-of-model-to-formdata-and-obtain-it-in-mvc/29293681#29293681) - instead of `data.append("model", JSON.stringify({ Text: 'test text', Id: 3 }));` it should be `data.append(Text, 'test text'); data.append(Id, 3);` –  Sep 26 '15 at 23:26
  • Thanks, now I see what was the problem with FormData! – Igor Goroshko Sep 27 '15 at 06:14

1 Answers1

3

Here is what I test using with MVC5 and IE11 / chrome

View

<script>
    $(function () {
        $("#form1").submit(function () {
            /*You can also inject values to suitable named hidden fields*/
            /*You can also inject the whole hidden filed to form dynamically*/
            $('#name2').val(Date); 
            var formData = new FormData($(this)[0]);
            $.ajax({
                url: $(this).attr('action'),
                type: $(this).attr('method'),
                data: formData,
                async: false,
                success: function (data) {
                    alert(data)
                },
                error: function(){
                    alert('error');
                },
                cache: false,
                contentType: false,
                processData: false
            });
            return false;
        });
    });
</script>

<form id="form1" action="/Home/Index" method="post" enctype="multipart/form-data">
    <input type="text" id="name1" name="name1" value="value1" />
    <input type="hidden" id ="name2" name="name2" value="" />
    <input name="file1" type="file" />
    <input type="submit" value="Sublit" />
</form>

Controller

public class HomeController : Controller
{
    [HttpGet]
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Index(HttpPostedFileBase file1, string name1, string name2)
    {
        var result = new List<string>();
        if (file1 != null)
            result.Add(string.Format("{0}: {1} bytes", file1.FileName, file1.ContentLength));
        else
            result.Add("No file");
        result.Add(string.Format("name1: {0}", name1));
        result.Add(string.Format("name2: {0}", name2));
        return Content(string.Join(" - ", result.ToArray()));
    }
}

Thanks to Silver89 for his answer

Community
  • 1
  • 1
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • The problem is that I don't have all required fields on the form, so the Model is constructed in JS code, just before sending POST request. – Igor Goroshko Sep 26 '15 at 22:43
  • @IgorGoroshko I think there are many ways to solve this problem, the one that you can test is to inject your values in suitable named hidden field of form. – Reza Aghaei Sep 26 '15 at 22:46
  • @IgorGoroshko Updated to inject value in hidden field. – Reza Aghaei Sep 26 '15 at 23:07
  • Thanks, this works, but the problem in my code is that we have a JS function, which accepts Model as parameter. This function is responsible for finding files in group of input:file elements and send those together with the model, so we don't have access to the form element. – Igor Goroshko Sep 27 '15 at 06:18
  • @IgorGoroshko as I said there are many ways to do that, for example, `data = new FormData(); data.append( 'file', $( '#file' )[0].files[0] );` – Reza Aghaei Sep 27 '15 at 15:57
  • @IgorGoroshko I think this is the answer of the question **"How to send ViewModel and a file in single Ajax POST request, in MVC 5?"** and can kindly be accepted to be more useful for future users :) – Reza Aghaei Sep 27 '15 at 16:00
  • Yes, thanks a lot! I was looking at all approaches, and finally decided to construct FormData programmatically. – Igor Goroshko Sep 27 '15 at 18:03