ToByteArrayAsync() - a more 'efficient' approach to converting Streams

Frequently, there is a need to convert a stream into an array of bytes. I came across this problem when uploading files in ASP.NET Core. StackOverflow has certainly a number of answers. In most cases, these answers require copying the array, which is no longer needed. .NET Core 2.0 introduced the concept of Span<T> and in .NET 2.1 we saw the rise of Memory<T>.

Both types enable access to the contiguous regions in memory. Span<T> had one key limitation, it had to be allocated on the stack and consequently could not be used in async operations. Memory<T> is similar but it is allocated on the managed heap and can be used in async operations.

Instead of doing streamVar.CopyTo(memoryStreamVar) and memoryStreamVar.ToArray() (which under the hood also does a copy), we can be a bit cleverer.

Firstly, we need to allocate an array of bytes equal to the length of the stream. IFormFile has a property Length which contains exactly that information.

Streams send data in chunks and have built-in support for the Memory type. When a new chunk of data arrives, we simply Slice off from memory to the number of bytes we have already added, we add how many bytes have been added Memory exposes a method Slice. All is async, so if a client has a particularly slow connection, we will wait until enough bytes are in the buffer without blocking the thread.

Leave a comment