Подтвердить что ты не робот

Работа с большими загрузками файлов в ASP.NET Core 1.0

Когда я загружаю большие файлы на свой веб-api в ASP.NET Core, среда выполнения загрузит файл в память до того, как моя функция для обработки и сохранения загрузки будет запущена. При больших загрузках это становится проблемой, так как она медленная и требует больше памяти. Для предыдущих версий ASP.NET есть некоторые статьи о том, как отключить буферизацию запросов, но я не могу найти никакой информации о как это сделать с ASP.NET Core. Можно ли отключить буферизацию запросов, чтобы я не исчерпал память на моем сервере все время?

4b9b3361

Ответ 1

Используйте Microsoft.AspNetCore.WebUtilities.MultipartReader, потому что он...

может анализировать любой поток [с] минимальной буферизацией. Он дает вам заголовки и тело каждого раздела по одному, а затем вы делаете то, что хотите, с телом этого раздела (буфер, отбрасывайте, записывайте на диск и т.д.).

Вот пример промежуточного программного обеспечения.

app.Use(async (context, next) =>
{
    if (!IsMultipartContentType(context.Request.ContentType))
    {
        await next();
        return;
    }

    var boundary = GetBoundary(context.Request.ContentType);
    var reader = new MultipartReader(boundary, context.Request.Body);
    var section = await reader.ReadNextSectionAsync();

    while (section != null)
    {
        // process each image
        const int chunkSize = 1024;
        var buffer = new byte[chunkSize];
        var bytesRead = 0;
        var fileName = GetFileName(section.ContentDisposition);

        using (var stream = new FileStream(fileName, FileMode.Append))
        {
            do
            {
                bytesRead = await section.Body.ReadAsync(buffer, 0, buffer.Length);
                stream.Write(buffer, 0, bytesRead);

            } while (bytesRead > 0);
        }

        section = await reader.ReadNextSectionAsync();
    }

    context.Response.WriteAsync("Done.");
});

Вот помощники.

private static bool IsMultipartContentType(string contentType)
{
    return 
        !string.IsNullOrEmpty(contentType) &&
        contentType.IndexOf("multipart/", StringComparison.OrdinalIgnoreCase) >= 0;
}

private static string GetBoundary(string contentType)
{
    var elements = contentType.Split(' ');
    var element = elements.Where(entry => entry.StartsWith("boundary=")).First();
    var boundary = element.Substring("boundary=".Length);
    // Remove quotes
    if (boundary.Length >= 2 && boundary[0] == '"' && 
        boundary[boundary.Length - 1] == '"')
    {
        boundary = boundary.Substring(1, boundary.Length - 2);
    }
    return boundary;
}

private string GetFileName(string contentDisposition)
{
    return contentDisposition
        .Split(';')
        .SingleOrDefault(part => part.Contains("filename"))
        .Split('=')
        .Last()
        .Trim('"');
}

Внешние ссылки

Ответ 2

В Controller вы можете просто использовать Request.Form.Files для доступа к файлам:

[HttpPost("upload")]
public async Task<IActionResult> UploadAsync(CancellationToken cancellationToken)
{
    if (!Request.HasFormContentType)
        return BadRequest();

    var form = Request.Form;
    foreach(var formFile in form.Files)
    {
        using(var readStream = formFile.OpenReadStream())
        {
            // Do something with the uploaded file
        }
    }


    return Ok();
}