nietras / Sep

World's Fastest .NET CSV Parser. Modern, minimal, fast, zero allocation, reading and writing of separated values (`csv`, `tsv` etc.). Cross-platform, trimmable and AOT/NativeAOT compatible.
http://nietras.com
MIT License
739 stars 29 forks source link

Sep does not support async only streams (such as IBrowserFile) #27

Open Shane88 opened 10 months ago

Shane88 commented 10 months ago

When trying to use Sep.Reader().From(stream) with a stream returned from IBrowserFile.OpenReadStream in the context of a user's browser in a .NET Blazor WASM application, it fails because Synchronous reads are not supported. To my understanding there is no other methods that can be used for Sep to use an asynchronous read from the supplied stream.

The stack trace will look like the following inside Blazor WASM:

crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Synchronous reads are not supported.
System.NotSupportedException: Synchronous reads are not supported.
   at Microsoft.AspNetCore.Components.Forms.BrowserFileStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at System.IO.StreamReader.ReadBuffer(Span`1 userBuffer, Boolean& readToUserBuffer)
   at System.IO.StreamReader.ReadSpan(Span`1 buffer)
   at System.IO.StreamReader.Read(Span`1 buffer)
   at nietras.SeparatedValues.SepReader.CheckCharsAvailableDataMaybeRead(Int32 paddingLength)
   at nietras.SeparatedValues.SepReader.EnsureInitializeAndReadData(Boolean endOfFile)
   at nietras.SeparatedValues.SepReader.MoveNext()
   at nietras.SeparatedValues.SepReader..ctor(Info info, SepReaderOptions options, TextReader reader)
   at nietras.SeparatedValues.SepReaderExtensions.FromWithInfo(Info info, SepReaderOptions options, TextReader reader)
   at nietras.SeparatedValues.SepReaderExtensions.From(SepReaderOptions options, Stream stream)

Note that BrowserFileStream belongs to AspNetCore.Components so I suspect this might also happen other frameworks like MVC but I haven't tested. The msdoc link for the method returning the async only stream is here (IBrowserFile.OpenReadStream(Int64, CancellationToken) Method)

Having had a good look over Seps docs I understand that async stream compatibility might be tricky and out of scope for the intended use of Sep. If that is the conclusion, it would be appreciated to update Sep docs to mention that.

Thinking about what async support might look like with Sep, I thought of the following.

// SepAsyncReader implements the IAsyncEnumerable pattern. 
using SepAsyncReader reader = Sep.Reader().FromAsync(stream);

await foreach (SepReader.Row row in reader)
{
   // Normal synchronous indexers at this point. 
   string myString = row["Column1"].ToString();
}

Cheers.

nietras commented 10 months ago

@Shane88 thank you for your interest in Sep and the detailed issue description. You are right that Sep does not support async usage currently and there are currently no immediate plans to support. However, I do hope to add it at some point, so I will leave this issue open to track it.

nietras commented 10 months ago

Just to be sure people are aware of this, you can of course copy the stream to a MemoryStream via await stream.CopyToAsync(memoryStream). This of course isn't particularly efficient but at least you can do that.