Загрузка файла на сервер исключает из памяти исключение

Я пытаюсь реализовать систему загрузки файлов с помощью asp.net web api, и у меня возникает проблема. Я пытаюсь получить данные многостраничной формы в поток памяти, чтобы он мог быть записан на диск или хранилище blob в зависимости от реализации уровня сервиса. Проблема в том, что он отлично работает для небольших файлов, но я пытаюсь загрузить файл размером 291 МБ и выкидывает исключение из памяти. Вот код:

if (!Request.Content.IsMimeMultipartContent())
{
    Request.CreateErrorResponse(HttpStatusCode.UnsupportedMediaType, "Request must be multipart.");
}

var provider = new MultipartMemoryStreamProvider();

try
{
    await Request.Content.ReadAsMultipartAsync(provider);

    var infoPart = provider.Contents.Where(x => x.Headers.ContentDisposition.Name.Replace("\"", string.Empty) == "fileInfo").SingleOrDefault();
    var filePart = provider.Contents.Where(x => x.Headers.ContentDisposition.Name.Replace("\"", string.Empty) == "filePart" && x.Headers.ContentDisposition.FileName != null).Single();
    byte[] file = null;

    using (Stream stream = filePart.ReadAsStreamAsync().Result)
    {
        using (MemoryStream memory = new MemoryStream())
        {
            stream.CopyTo(memory);
            file = memory.ToArray();
        }
    }

    string fileContentType = filePart.Headers.ContentType.MediaType;

    FileDto result = _fileService.AddFileToResource(Variables);
    string uri = Url.Link("DefaultGet", new { id = result.ID });
    return Request.CreateResponse(HttpStatusCode.OK);

Часть, которая выдает ошибку, находится на

await Request.Content.ReadAsMultipartAsync(provider);

Точная ошибка

Ошибка записи MIME частичной части тела в выходной поток.

с внутренним исключением

Было исключено исключение типа 'System.OutOfMemoryException'.

Я попытался создать пользовательский BufferPolicySelector, как показано во втором ответе этого сообщения и во многих других местах, но это, похоже, совсем не помогает.

Я также добавил в свой web.config:

<httpRuntime targetFramework="4.5" maxRequestLength="307200"/>

и

<security>
  <requestFiltering>
    <requestLimits maxAllowedContentLength="367001600"/>
  </requestFiltering>
</security>

Ответы

Ответ 1

Одним из решений было бы использовать MultipartFormDataStreamProvider вместо MultipartMemoryStreamProvider, чтобы избежать исключения из памяти во время вызова

Request.Content.ReadAsMultipartAsync(..)

У меня возникла аналогичная проблема при попытке использовать MemoryStreamProvider при чтении содержимого файла MultiPart для большого файла ( > 100 МБ). Работа, которая работала для меня, заключалась в использовании MultipartFormDataStreamProvider. Файл записывается на диск во время вызова ReadAsMultipartAsync и может быть позже загружен обратно, если вам это нужно в памяти.

Вот пример, взятый из:

Отправка данных формы HTML в веб-API: загрузка файлов и многостраничный MIME

    string root = HttpContext.Current.Server.MapPath("~/App_Data");
    var provider = new MultipartFormDataStreamProvider(root);

    try
    {
        // Read the form data.
        await Request.Content.ReadAsMultipartAsync(provider);

        // This illustrates how to get the file names.
        foreach (MultipartFileData file in provider.FileData)
        {
            Trace.WriteLine(file.Headers.ContentDisposition.FileName);
            Trace.WriteLine("Server file path: " + file.LocalFileName);
        }
        return Request.CreateResponse(HttpStatusCode.OK);
    }
    catch(...)

Ответ 2

проверьте свой webconfig для ограничений на загрузку файлов

<system.webServer>
        <security>
            <requestFiltering>
                <requestLimits maxAllowedContentLength="524288000"/>
            </requestFiltering>
        </security>
</system.webServer>

От OP Edit:

<httpRuntime targetFramework="4.5" maxRequestLength="307200"/>

maxRequestLength находится в Кб - это порог буферизации, вы запрашиваете буфер 300 МБ - возможно, не очень хорошо. установите его ниже

Ответ 3

Проверьте права доступа к папке на сервере.

или

Поместите httpRuntime maxRequestLength в файл web.config, например:

<httpRuntime maxRequestLength="5242880" />