Как обрабатывать несколько загрузок файлов HTML5 в ASP.NET MVC?

Я нашел следующий отличный поток с объяснением того, как выполнять загрузку файлов через AJAX/Jquery с помощью нового API-интерфейса HTML5 FormData​​p >

Здесь немного обновленная версия этого кода с новым синтаксисом JQuery 1.8+

$(':button').click(function(){
    var formData = new FormData($('form')[0]);
    $.ajax({
        url: '/Upload',  //my ASP.NET MVC method
        type: 'POST',
        // handle the progress report
        xhr: function() {  // Custom XMLHttpRequest
            var myXhr = $.ajaxSettings.xhr();
            if(myXhr.upload){ // Check if upload property exists
                myXhr.upload.addEventListener('progress',progressHandlingFunction,    false); // For handling the progress of the upload
            }
            return myXhr;
        },

        // Form data
        data: formData,

        //Options to tell jQuery not to process data or worry about content-type.
        cache: false,
        contentType: false,
        processData: false
    })
    .done(function(){
        alert("success");
    })
    .fail(function(){
        alert("error");
    });
});

function progressHandlingFunction(e){
    if(e.lengthComputable){
        $('progress').attr({value:e.loaded,max:e.total});
    }
}

и здесь форма

<form enctype="multipart/form-data">
    <input name="file" type="file" />
    <input type="button" value="Upload" />
</form>
<progress></progress>

На стороне сервера у нас есть что-то вроде этого.

[HttpPost]
public string Upload(HttpPostedFileBase file)
{
    // do something with file
    return "you uploaded a file called " + file.FileName;
}

Это отлично работает. Если вы решите использовать атрибут "multiple" в диалоговом окне файла и отправить несколько файлов.

<form enctype="multipart/form-data">
    <input name="file" type="file" multiple="multiple" />
    <input type="button" value="Upload" />
</form>
<progress></progress>

Вы найдете различные страницы в Интернете, предлагающие следующие решения.

public string Upload(IEnumerable<HttpPostedFileBase> files)
{
    foreach(var file in files)
         ...
}

К сожалению. Не работает

public string Upload(List<HttpPostedFileBase> files)
{
    foreach(var file in files)
         ...
}

Неа. Не работает.

public string Upload(IEnumerable files)
{
    foreach(var file in files)
         ...
}

Не компилирует

public string Upload(HttpPostedFileBase[] files)
{
    foreach(HttpPostedFileBase file in files)
         ...
}

Угадайте, что? Не работает. Давайте попробуем обработать Request.Files. Хороший старый надежный Request.Files. Никогда не сработает.

public string Upload()
{
    foreach (HttpPostedFileBase uf in Request.Files)
         ...
}

Предупреждение о спойлере: оно не работает.

Ага. Понял! Вместо этого я буду перебирать ключи в Request.Files.

public string Upload()
{
    foreach(var key in Request.Files.AllKeys)
    {
        var file = Request.Files[key];
    }
}

Опять же, это не сработает.

Ответы

Ответ 1

Что работает, является следующим, из блога о всегда надежном и динамично развивающемся Rick Strahl

public string Upload()
{
    for (int i = 0; i < Request.Files.Count; i++)
    {
        var file = Request.Files[i];
    } 
}

Причина этого заключается в том, что коллекция файлов, переданных в Request.Files , имеет одно и то же имя, потому что они происходят из диалогового окна загрузки отдельных файлов.

серверный метод передается одним объектом, содержащим файлы, и по какой-то причине Request.Files - это единственный способ получить его.

Надеюсь, что я немного избавился от головной боли, добавив это.

Ответ 2

В моем случае то, что сработало для меня, привязывало все мои файлы к полю ViewModel. ViewModel будет моделью, которую я использую для моего интерфейса.

@using School.ViewModels
@model UserProfileViewModel


<form enctype="multipart/form-data">
<input id="username"name="username" type="text" />
<input name="Myfiles" type="file" multiple="multiple" />
<input type="button" value="Upload" />
</form>

UserProfileViewModel.cs

namespace School.ViewModels
{
    public class UserProfileViewModel
    {
        public long Username { get; set; }

        public List<HttpPostedFileBase> Myfiles { get; set; }
    }
}

UserProfilePicturesController.cs

public ActionResult Create([Bind(Include="Username,Myfilese")] UserprofileViewModel userprofileViewModel)
{
     var files = userprofileViewModel.Myfiles;
     foreach(HttpPostedFileBase file in files)
     {
         //do something here
     }
}