Why does StreamReader.ReadToEnd work but not Stream.Read?

InstilledBee

I am trying to get the body of a request in an ASP.NET Core controller as a byte[] array. Here is what I initially wrote:

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

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

This code works, but only for small requests (around ~20KB). For larger requests it fills up the first 20,000 or so bytes in the array, then the rest of the array is empty.

I used some code in the top answer here, and was able to read the entire request body successfully after rewriting my code:

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);

Why is StreamReader.ReadToEnd() able to read the entire request body successfully, while Stream.Read() can't? Reading the request stream twice feels like a hack. Is there a better way to go about this? (I only need to read the stream into a byte array once)

canton7

Remember that you're trying to read request.Body before all of the request has been received yet.

Stream.Read behaves like this:

  1. If the end of the stream has been reached, return 0
  2. If there are no bytes available which haven't already been read, block until at least 1 byte is available
  3. If 1 or more new bytes are available, return them straight away. Don't block.

As you can see, if the whole body hasn't been received yet, request.Body.Read(...) will just return the part of the body that has been received.

StreamReader.ReadToEnd() calls Stream.Read in a loop, until it finds the end of the stream.

You should probably call Stream.Read in a loop as well, until you've read all of the bytes:

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;
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Why is StreamReader.ReadToEnd() throwing in .NET Core but not .NET Framework?

Does disposing streamreader close the stream?

Why does an await cause my stream to be read

Why stream peek does not work properly in HashMap

Why AssignerWithPunctuatedWatermarks does not work in my data stream?

StreamReader.ReadToEnd returns file path

streamReader.ReadToEnd() return just header OpenXML

Why does the FileReader stream read 237, 187, 191 from a textfile?

Read HttpContent stream until a character limit using StreamReader

What is the purpose of StreamReader when Stream.Read() exists?

Why does SpEL not work in Spring Boot and Spring Cloud Stream @SendTo

Why does storing a stream of base64 data not work?

RTSP stream doesn't work on python, But does on VLC. why?

C# socket StreamReader.ReadToEnd wait forever

Why does this "while read" work in a terminal, but not in a shell script?

Why does "info()" not work even though the "read" field changes?

Why asyncio.StreamReader.read return didn't block the thread?

Why does splitting my $PATH with `read -r -a line` work but not with `while read -r line`?

Why does the read-only test work for a read-write file when using _access?

Python and UIO devices: Why does mmap.read() work and os.read() fail?

read encoding identifier with StreamReader

Read the next char in a StreamReader

Read many of the StreamReader

Why does one version of this Java stream work on a Static Map while the other fails?

Why does distinct work via flatMap, but not via map's "sub-stream"?

Why does this Delay future inside poll() not work in my custom Stream type?

Why does this stream return no element?

Read multiple lines with StreamReader with StreamReader.Peek

Why does a '.' work in chown?