Загрузка файла не попадает в контроллер до завершения загрузки и временно сохраняется на диск - PullRequest
2 голосов
/ 09 июля 2020

Давайте представим, что я запускаю. NET Core API на устройстве с 1 ГБ памяти и 1 ГБ ОЗУ. Я хочу загрузить файл со своего веб-сайта прямо на FTP-сервер, без кеширования файла в памяти или на диске. У меня это работает для загрузки файлов, поскольку я в основном выступаю в качестве прокси, открывая файл FTP в потоке, а затем передавая его прямо на HttpContext.Request.Body.

Для загрузки я хочу нажать на контроллер немедленно. Теперь я вижу, что он кешируется на диск, и это, вероятно, из-за моего атрибута EnableBuffering. У меня есть обычный <form method="post" enctype="multipart/form-data">, который отправляет POST на мой. NET Core backend. Контроллер выглядит так:

[EnableBuffering]
[RequestFormLimits(ValueLengthLimit = int.MaxValue, MultipartBodyLengthLimit = long.MaxValue)]
[HttpPost("[action]")]
public async Task<IActionResult> Upload(string path)
{
    if (!IsMultipartContentType(HttpContext.Request.ContentType))
        return BadRequest("Not multipart request");

    await _fileProvider.Upload(path);

    return Ok();
}

EnableBuffering:

public class EnableBufferingAttribute : Attribute, IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        context.HttpContext.Request.EnableBuffering();
    }

    public void OnResourceExecuted(ResourceExecutedContext context) {}
}

Logi загрузки c:

public async Task Upload(string path)
{
    const int buffer = 8 * 1024;

    var request = _httpContextAccessor.HttpContext.Request;
    var boundary = request.GetMultipartBoundary();
    var reader = new MultipartReader(boundary, request.Body, buffer);
    var section = await reader.ReadNextSectionAsync();

    using (var client = await _ftpHelper.GetFtpClient())
    {
        while (section != null)
        {
            var fileSection = section.AsFileSection();

            if (fileSection != null)
            {
                var fileName = fileSection.FileName;

                var uploadPath = Path.Combine(path, fileName);

                var stream = await client.OpenWriteAsync(uploadPath);
                await section.Body.CopyToAsync(stream, buffer);
            }

            section = await reader.ReadNextSectionAsync();
        }
    }
}

Если я не включаю буферизацию, я get:

System.IO.IOException: неожиданный конец потока, контент, возможно, уже был прочитан другим компонентом.

Однако, включив буферизацию, я могу см. там написано:

Убедитесь, что requestBody можно читать несколько раз. Обычно тела запросов буферизируются в памяти; записывает запросы размером более 30 Кбайт на диск .

Так что эта часть имеет смысл. Однако как мне обойти эту проблему? Если я устанавливаю точку останова в первой строке метода Upload(), а затем начинаю загрузку, он сначала загружает файл И ЗАТЕМ достигает точки останова.

Могу ли я обойти это чтобы он сразу попал в мой контроллер и начал загрузку на FTP-сервер, без предварительного сохранения на диск?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...