Почему StreamReader.ReadToEnd работает, а не Stream.Read? - PullRequest
2 голосов
/ 23 октября 2019

Я пытаюсь получить тело запроса в контроллере ASP.NET Core в виде массива byte[]. Вот что я изначально написал:

var declaredLength = (int)request.ContentLength;
byte[] fileBuffer = new byte[declaredLength];

request.Body.Read(fileBuffer, 0, declaredLength);

Этот код работает, но только для небольших запросов (около ~ 20 КБ). Для больших запросов он заполняет первые 20 000 или около того байтов в массиве, затем остальная часть массива пуста.

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

var declaredLength = (int)request.ContentLength;
byte[] fileBuffer = new byte[declaredLength];

// need to enable, otherwise Seek() fails
request.EnableRewind();

// using StreamReader apparently resolves the issue
using (var reader = new StreamReader(request.Body, Encoding.UTF8, true, 1024, true))
{
    reader.ReadToEnd();
}

request.Body.Seek(0, SeekOrigin.Begin);
request.Body.Read(fileBuffer, 0, declaredLength);

Почему StreamReader.ReadToEnd() может успешно прочитать все тело запроса, а Stream.Read() - нет? Чтение потока запросов дважды выглядит как хак. Есть ли лучший способ сделать это? (Мне нужно только один раз прочитать поток в байтовый массив)

1 Ответ

2 голосов
/ 23 октября 2019

Помните, что вы пытаетесь прочитать request.Body до того, как все запросы будут получены.

Stream.Read ведет себя так:

  1. Если достигнут конец потока, вернуть 0
  2. Если нет доступных байтов, которые еще не были прочитаны, блокируйте, пока не будет доступен хотя бы 1 байт
  3. Если доступны 1 или более новых байтов, верните их немедленно. Не блокируйте.

Как видите, если все тело еще не получено, request.Body.Read(...) просто вернет часть тела, которая была получена.

StreamReader.ReadToEnd() вызывает Stream.Read в цикле , пока он не найдет конец потока.

Вам, вероятно, следует также вызвать Stream.Read в цикле, пока вы не 'мы прочитали все байты:

byte[] fileBuffer = new byte[declaredLength];
int numBytesRead = 0;
while (numBytesRead < declaredLength)
{
    int readBytes = request.Body.Read(fileBuffer, numBytesRead, declaredLength - numBytesRead);
    if (readBytes == 0)
    {
        // We reached the end of the stream before we were expecting it
        // Might want to throw an exception here?
    }
    numBytesRead += readBytes;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...