Используйте formdata append с @HTML.BeginForm без вызова ajax

То, что я пытаюсь достичь, - добавить файл в сообщение, которое я получил из поля drag & drop с javascript. Проблема в том, что я не хочу читать все поля ввода и отправлять данные по вызову ajax, я хочу использовать метод отправки по умолчанию из @HTML.BeginForm. Когда я это делаю, multipart действительно не содержит файл.

(Внимание: он работает, когда я просто отправлю файл или когда я прочитал все поля ввода вручную и отправлю с помощью отдельного ajax.)

Мой код: Drag & Drop js:

var file;
var isDragged = false;
var formData;
function dropHandler(ev) {
    isDragged = true;
    ev.preventDefault();
    // Use DataTransfer interface to access the file(s)
    for (var i = 0; i < ev.dataTransfer.files.length; i++) {
        file = ev.dataTransfer.files[i];

        formData = new FormData($("#form"));
        formData.append("File.PayLoad", file);
        formData.append("File.FileMetadataId", $('#File_FileMetadataId').val())
        formData.append("File.FileObjectId", $('#File_FileObjectId').val())      
   }
}

HTML:

  @using (Html.BeginForm("Edit", "DocumentTemplates", FormMethod.Post, new { role = "form", enctype = "multipart/form-data", id = "form" }))
    {
     @Html.AntiForgeryToken()
     <div class="row">
         <div class="col-xs-4">
             @Html.LabelFor(model => model.Language)
         </div>
         <div class="col-xs-8">
             @Html.HiddenFor(model => model.Language) @Html.DisplayFor(model => model.Language)
         </div>
     </div>
     <div class="row">
         <div class="col-xs-8">
             @Html.TextBoxFor(model => model.File.Payload, new { type = "file", @id = "browseFile", ondrop = "dropHandler(event);", ondragover = "dragOverHandler(event);" }) 
             @Html.ValidationMessageFor(model => model.File.Payload, null, new { @class = "text-danger" }) or Drag & Drop a File.
         </div>
     </div>
    }

Запрос в Fiddler с пустым Имя файла:

-----------------------------7e27b381715d4
Content-Disposition: form-data; name="File.FileMetadataId"

44
-----------------------------7e27b381715d4
Content-Disposition: form-data; name="File.FileObjectId"

44
-----------------------------7e27b381715d4
Content-Disposition: form-data; name="File.Payload"; filename=""
Content-Type: application/octet-stream


-----------------------------7e27b381715d4--

ОБНОВЛЕНИЕ: Я узнал, вы можете перезаписать файлы из ввода файла, но только в Chrome. Так как мне нужно, чтобы он работал над IE 11, это не помогает мне, но, возможно, это помогает кому-то другому. Вам не нужно добавлять все поля формы, но просто установите файл типа ввода в ваш упавший файл и отправьте...

Ответ 1

У вас есть несколько проблем. Одна из проблем - это код ниже. Вы пропустили один } в своем коде.

Если вы поместите его так, как показано ниже, последнее значение просто хранится в file который является неправильным.

for (var i = 0; i < ev.dataTransfer.files.length; i++) {
        file = ev.dataTransfer.files[i];
} // missing }

Если вы поместите его так, как formData ниже, последнее значение просто хранится в formData который является неправильным.

function dropHandler(ev) {
    isDragged = true;
    ev.preventDefault();
    // Use DataTransfer interface to access the file(s)
    for (var i = 0; i < ev.dataTransfer.files.length; i++) {
        file = ev.dataTransfer.files[i];

    formData = new FormData($("#form"));
    formData.append("File.PayLoad", file);
    formData.append("File.FileMetadataId", $('#File_FileMetadataId').val());
    formData.append("File.FileObjectId", $('#File_FileObjectId').val());    
   }
} // missing }

Вторая проблема - ev.dataTransfer.files. Как вы можете видеть в перетаскивании файла, лучше проверить ev.dataTransfer.items и иногда у него есть ваши файлы, а ev.dataTransfer.files пуст.

Наконец, вы можете сделать это следующим образом:

function dropHandler(ev) {
    isDragged = true;
    ev.preventDefault();    

    formData = new FormData($("#form"));

    if (ev.dataTransfer.items) {
        // Use DataTransferItemList interface to access the file(s)
        for (var i = 0; i < ev.dataTransfer.items.length; i++) {
            // If dropped items aren't files, reject them
            if (ev.dataTransfer.items[i].kind === 'file') {
                var file = ev.dataTransfer.items[i].getAsFile();
                formData.append("File.PayLoad" + i, file);
            }
        }
    } else {
        // Use DataTransfer interface to access the file(s)
        for (var i = 0; i < ev.dataTransfer.files.length; i++) {
            file = ev.dataTransfer.files[i];
            formData.append("File.PayLoad" + i, file);
        }
    }
}