Tewr / BlazorFileReader

Library for creating read-only file streams from file input elements or drop targets in Blazor.
MIT License
426 stars 61 forks source link

Uploading to file on Server-side Blazor #156

Closed SpontaneousDuck closed 4 years ago

SpontaneousDuck commented 4 years ago

Describe the bug I am writing a Server side Blazor app and am trying to upload a file to a local file on the server. I can open the FileStream successfully and create the file I want to write to. But when calling CopyToAsync the code hangs and does not write anything to the file. Both streams are at position=0 and I can see the correct length in the uploaded FileStream when debugging. the Stream is just not copied to me opened FileStream.

To Reproduce I copied the code from Index.razor on the Demo app into my project and changed the stream copy part to this:

using(var fs = new FileStream($"data/{Guid.NewGuid()}.bin", FileMode.CreateNew))
{
    using (var fi = await file.OpenReadAsync())
     {
         fs.Position = 0;
         await fi.CopyToAsync(fs, BufferSize, cancellationTokenSource.Token);
     }
}

Expected behavior Stream is copied to the FileStream I created.

Project type 'Server-side'/'SSB'

Environment

Thanks for the help!!

Tewr commented 4 years ago

Well I'd say... I can't reproduce this in my demo project in debug or release. but if I create a new server-side project project and reference the nuget package... yes there is a timeout. There is some kind of compliation bug. Perhaps the optimizer.

CopyToAsync is a method from the framework base class Stream. Here is the implementation:

 byte[] buffer = new byte[bufferSize];
 int bytesRead;
 while ((bytesRead = await ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
 {
       await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
 }

If you use that code in place of CopyToAsync it works. ReadAsync should be called on fi, destination is your fs. You can use that as a workaround in the meantime while I investigate.

Tewr commented 4 years ago

Note to self: this is too strange, must be related to the signalR buffersize, in some way I don't understand currently.

SpontaneousDuck commented 4 years ago

Perfect! I replaced my code with the code you recommended and it worked for me perfectly. FYI, I did not do anything to change the SignalR buffer size in my project. Thanks for the help and good work!

Tewr commented 4 years ago

OK so this is confirmed, related to the SignalR buffer size configuration which is mentioned in the readme. CopyToAsync poses no problem if the buffer is set like mentioned here. However, it's a bit weird that it works with my workaround. That means that CopyToAsync has some other implementation than the one mentioned above. Which uses a bigger buffer size. I remember that there used to be a console error when going over the buffer, but there does not seem to be one anymore. The channel just fails.

Tewr commented 4 years ago

I guess I was looking at old code.

The actual code is here and is a lot more complicated than the code above. Difficult to see what the buffersize will be in all cases here. In any case, the evidence show that at some point the buffer size used for the actual transfer will be larger than the one passed to CopyToAsync.