Загрузка файла через AJAX в ASP.NET MVC и Web API

Последнее обновление: 1.11.2015

В статье Загрузка файлов на сервер в ASP.NET MVC были рассмотрены общие моменты оптравки файлов на сервер в обычном запросе POST. Но если мы используем Ajax-запросы, то загрузка файлов будет иметь свои особенности.

Сначала определим метод в контроллере MVC :

[HttpPost]
public JsonResult Upload()
{
    foreach (string file in Request.Files)
    {
        var upload = Request.Files[file];
        if (upload != null)
        {
            // получаем имя файла
            string fileName = System.IO.Path.GetFileName(upload.FileName);
            // сохраняем файл в папку Files в проекте
            upload.SaveAs(Server.MapPath("~/Files/" + fileName));
        }
    }
    return Json("файл загружен");
}

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

После сохранения файла пользователю отдается результат в виде строки.

Код представления тогда будет выглядеть следующим образом:

@{
    ViewBag.Title = "Home Page";
}

<div>
    <input type="file" name="upload" id="uploadFile"  /><br />
    <button id="submit">Загрузить</button>
</div>

@section scripts{
<script type="text/javascript">

    $('#submit').on('click', function (e) {
        e.preventDefault();
        var files = document.getElementById('uploadFile').files;
        if (files.length > 0) {
            if (window.FormData !== undefined) {
                var data = new FormData();
                for (var x = 0; x < files.length; x++) {
                    data.append("file" + x, files[x]);
                }

                $.ajax({
                    type: "POST",
                    url: '@Url.Action("Upload", "Home")',
                    contentType: false,
                    processData: false,
                    data: data,
                    success: function (result) {
                        alert(result);
                    },
                    error: function (xhr, status, p3) {
                        alert(xhr.responseText);
                    }
                });
            } else {
                alert("Браузер не поддерживает загрузку файлов HTML5!");
            }
        }
    });
</script>
}

Нам не нужна стандартная форма, все делается через ajax. Сначала получаем все выбранные файлы:

var files = document.getElementById('uploadFile').files

Затем формируем объект FormData, в который добавляем все выбранные файлы:

var data = new FormData();
for (var x = 0; x < files.length; x++) {
    data.append("file" + x, files[x]);
}

И отсылаем их на сервер.

Асинхронная загрузка файлов в WebAPI

В Web API контроллер будет выглядеть следующим образом:

public class ValuesController : ApiController
{
	public async Task<IHttpActionResult> Post()  
    {
        if (!Request.Content.IsMimeMultipartContent())
        {
            return BadRequest();
        }
        var provider = new MultipartMemoryStreamProvider();
        // путь к папке на сервере
        string root = System.Web.HttpContext.Current.Server.MapPath("~/Files/");
        await Request.Content.ReadAsMultipartAsync(provider);

        foreach (var file in provider.Contents)
        {
            var filename = file.Headers.ContentDisposition.FileName.Trim('\"');
            byte[] fileArray = await file.ReadAsByteArrayAsync();

            using (System.IO.FileStream fs = new System.IO.FileStream(root + filename, System.IO.FileMode.Create))
            {
                await fs.WriteAsync(fileArray, 0, fileArray.Length);
            }
        }
        return Ok("файлы загружены");
    }
}

Здесь используется асинхронная обработка запроса. Вначале метод IsMultipartContent() проверяет, содержит ли запрос корректные данные. Если нет, то возвращаем статусный код 401.

Для асинхронного чтения с потока создается провайдер:

var provider = new MultipartMemoryStreamProvider();
Request.Content.ReadAsMultipartAsync(provider);

После считывания потока свойство provider.Contents будет содержать все считанные значения, в том числе и файлы. И в цикле проходим по всем файлам и читаем их в массив байтов:

byte[] fileArray = await file.ReadAsByteArrayAsync();

Затем с помощью объекта FileStream считанный массив сохраняется на диске в папке проекта.

Представление будет тем же, что и для MVC, за исключением url запроса:

$.ajax({
    type: "POST",
    url: 'api/values/post',
    contentType: false,
    processData: false,
    data: data,
    success: function (result) {
        alert(result);
    },
    error: function (xhr, status, p3) {
        alert(status);
    }
});
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850