Как отправить ViewModel и файл в одном запросе Ajax POST в MVC 5?

У меня есть приложение ASP.NET MVC 5. И я пытаюсь отправить запрос POST с данными модели, а также включить выбранные пользователем файлы. Вот моя ViewModel (упрощенная для ясности):

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

Вот действие контроллера:

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

    return View("Index");
}

Элемент ввода HTML:

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

И код JavaScript:

$('#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) { }
    });
});

Проблема в том, что когда запрос достигает действия контроллера, у меня есть файлы и «userId», но параметр «модель» всегда равен нулю. Я делаю что-то неправильно при заполнении объекта FormData?


person Igor Goroshko    schedule 26.09.2015    source источник
comment
С contentType: application/json он не будет отправлять файлы.   -  person Igor Goroshko    schedule 27.09.2015
comment
См. >этот ответ - вместо data.append("model", JSON.stringify({ Text: 'test text', Id: 3 })); должно быть data.append(Text, 'test text'); data.append(Id, 3);   -  person    schedule 27.09.2015
comment
Спасибо, теперь я вижу, в чем была проблема с FormData!   -  person Igor Goroshko    schedule 27.09.2015


Ответы (1)


Вот что я тестирую с помощью MVC5 и IE11/chrome

Просмотреть

<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>

Контроллер

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

Спасибо Silver89 за его ответ.

person Reza Aghaei    schedule 26.09.2015
comment
Проблема в том, что у меня нет всех обязательных полей в форме, поэтому Модель создается в JS-коде непосредственно перед отправкой POST-запроса. - person Igor Goroshko; 27.09.2015
comment
@IgorGoroshko Я думаю, что есть много способов решить эту проблему, один из которых вы можете проверить, - это ввести свои значения в подходящее именованное скрытое поле формы. - person Reza Aghaei; 27.09.2015
comment
@IgorGoroshko Обновлено для ввода значения в скрытое поле. - person Reza Aghaei; 27.09.2015
comment
Спасибо, это работает, но проблема в моем коде в том, что у нас есть функция JS, которая принимает модель в качестве параметра. Эта функция отвечает за поиск файлов в группе элементов input:file и отправку их вместе с моделью, поэтому у нас нет доступа к элементу формы. - person Igor Goroshko; 27.09.2015
comment
@IgorGoroshko, как я уже сказал, есть много способов сделать это, например, data = new FormData(); data.append( 'file', $( '#file' )[0].files[0] ); - person Reza Aghaei; 27.09.2015
comment
@IgorGoroshko Я думаю, что это ответ на вопрос Как отправить ViewModel и файл в одном запросе Ajax POST в MVC 5? и может быть любезно принят как более полезный для будущих пользователей :) - person Reza Aghaei; 27.09.2015
comment
Да, большое спасибо! Я рассматривал все подходы и, наконец, решил построить FormData программно. - person Igor Goroshko; 27.09.2015