ASP.NET Core 6: Поток HttpContext.Request.Body не может превышать 4096 байт

Вопрос или проблема

Я пишу программу на ASP.NET Core 6, которая получает много файлов и записывает их в базу данных SQLite.

Я использую следующий код на клиенте для отправки файла:

var request = new HttpRequestMessage() 
                  {
                      Method = HttpMethod.Post,
                      RequestUri = new Uri(server.serverBase + "/api/snapshot/UploadFile"),
                  };

using (FileStream filestream = File.Open(file.getFilePath(), FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
{
        var length = filestream.Length.ToString();

        var streamContent = new StreamContent(filestream, 16384);
        streamContent.Headers.Add("Content-Type", "application/octet-stream");
        streamContent.Headers.Add("Content-Length", length);

        request.Content = streamContent;

        var httpClient = new HttpClient();
        httpClient.Timeout = new TimeSpan(0, 2, 0);

        var response = httpClient.SendAsync(request).Result;
        //Console.WriteLine(response.Content.ReadAsStringAsync().Result);
}

А следующий код на сервере для получения потока:

[HttpPost("UploadFile")]
[RequestSizeLimit(100000000000)]
public async Task<IActionResult> UploadFile()
{
    int CHUNK_SIZE = 1024 * 1024; //Размер кусочка 1 МБ

    using (Stream stream = HttpContext.Request.Body) 
    {
        var buffer = new byte[CHUNK_SIZE];
        int bytesRead;
        int chunkNumber = 0;
        long totalNumBytes = 0;
        int progress = 0;

        while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0) 
        {
            System.Diagnostics.Debug.WriteLine(bytesRead);
            await ProcessChunk(buffer, bytesRead, chunkNumber, totalNumBytes);
            chunkNumber++;
        }
    }

    return Ok("Файл успешно загружен и разбит на кусочки.");
}

Тем не менее, несмотря на то, что размер буфера составляет 1048576 байт, вывод отладки всегда составляет 4096, т.е. я читаю только 4096 байт за каждый “кусочек” потока.

Как я могу увеличить размер буфера больше 4096 байт?

Моя конечная цель – взять каждый “кусочек” и сохранить его в базе данных как blob, большинство отправляемых файлов примерно 3KB, поэтому я планировал изменить размер каждого “кусочка” на 1KB, чтобы использовать меньше строк для каждого кусочка файла.

Я пробовал:

  • Изменить лимиты Kestrel
  • “enableBuffering” на объекте запроса
  • Использовать MemoryStream

Я ожидал, что буфер потока HttpContext.Request.Body увеличится более чем на 4096 байт, но, похоже, я не могу превысить этот предел.

Вам стоит увеличить maxAllowedContentLength в вашем web.config

<configuration>
  <system.webServer>
    <security>
      <requestFiltering removeServerHeader="true">
        <requestLimits maxAllowedContentLength="2147483647" />

Ответ или решение

В вашем случае проблема с ограничением потока HttpContext.Request.Body, который всегда равен 4096 байт, может быть связана с настройками Kestrel или IIS, а также с конфигурированием вашего ASP.NET Core приложения.

Чтобы решить вашу проблему, рассмотрим несколько важных моментов:

1. Увеличение ограничений на размер запроса в Kestrel

Убедитесь, что вы увеличили ограничения на размер запросов в конфигурации Kestrel. Эти параметры можно настроить в методе ConfigureServices класса Startup. Например:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<KestrelServerOptions>(options =>
    {
        options.Limits.MaxRequestBodySize = 104857600; // Устанавливаем 100MB
    });

    // Другие настройки сервисов
}

2. Настройка размера тела запроса для IIS

Если ваше приложение размещено в IIS, необходимо установить максимально допустимый размер тела запроса в web.config. Убедитесь, что у вас есть следующая конфигурация:

<configuration>
  <system.webServer>
    <security>
      <requestFiltering removeServerHeader="true">
        <requestLimits maxAllowedContentLength="2147483647" /> <!-- 2GB в байтах -->
      </requestFiltering>
    </security>
  </system.webServer>
</configuration>

3. Использование EnableBuffering

Хотя вы упомянули, что пробовали использовать EnableBuffering, убедитесь, что вы вызываете его в вашем методе действия перед чтением потока:

[HttpPost("UploadFile")]
[RequestSizeLimit(100000000000)]
public async Task<IActionResult> UploadFile()
{
    HttpContext.Request.EnableBuffering(); // Включаем буферизацию

    int CHUNK_SIZE = 1024 * 1024; // 1 MB chunk size

    using (Stream stream = HttpContext.Request.Body)
    {
        var buffer = new byte[CHUNK_SIZE];
        int bytesRead;
        int chunkNumber = 0;
        long totalNumBytes = 0;

        while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
        {
            // Обработка загруженного куска
            await ProcessChunk(buffer, bytesRead, chunkNumber, totalNumBytes);
            chunkNumber++;
        }
    }

    return Ok("Файл загружен и chunked успешно.");
}

4. Некоторые дополнительные соображения

  • Асинхронность: Убедитесь, что вы не блокируете поток вашего приложения (например, с помощью .Result) при отправке запроса с клиента, так как это может привести к проблемам с производительностью или тайм-аутами.

  • Обработка ошибок: Не забудьте обрабатывать возможные исключения как на стороне клиента, так и на стороне сервера для лучшего контроля над ошибками.

Заключение

Проведя вышеперечисленные шаги, вы сможете увеличить лимиты потока и успешно обрабатывать загружаемые файлы. Убедитесь, что вы проверили все настройки, и зафиксируйте возможные проблемы, если пользователи все еще сталкиваются с ограничениями по размеру данных. Если у вас есть дополнительные вопросы, не стесняйтесь задавать их.

Оцените материал
Добавить комментарий

Капча загружается...