Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spreadsheet.Open crash in Kestrel web server (.NET 6) since synch reads are not allowed #1109

Closed
maloo opened this issue Jan 5, 2022 · 6 comments

Comments

@maloo
Copy link

maloo commented Jan 5, 2022

Description

When opening an excel document in .NET 6 (Kestrel web server) I get an exception that synch reads are not allowed. And this is for a good reason, no libraries should force user to do blocking operations because it limits where the library can be used (on a web server in this case).

Information

  • .NET Target: .NET 6
  • DocumentFormat.OpenXml Version: 2.15

Repro

Call Spreadsheet.Load from a ASP.NET Core Action or in Blazor Server callback.

Observed

System.NotSupportedException: Synchronous reads are not supported.
at Microsoft.AspNetCore.Components.Forms.BrowserFileStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.Stream.CopyTo(Stream destination, Int32 bufferSize)
at System.IO.Stream.CopyTo(Stream destination)
at System.IO.Compression.ZipArchive..ctor(Stream stream, ZipArchiveMode mode, Boolean leaveOpen, Encoding entryNameEncoding)
at System.IO.Packaging.ZipPackage..ctor(Stream s, FileMode packageFileMode, FileAccess packageFileAccess)
at System.IO.Packaging.Package.Open(Stream stream, FileMode packageMode, FileAccess packageAccess)
at DocumentFormat.OpenXml.Packaging.PackageLoader.OpenCore(Stream stream, Boolean readWriteMode)
at DocumentFormat.OpenXml.Packaging.SpreadsheetDocument.Open(Stream stream, Boolean isEditable, OpenSettings openSettings)
at DocumentFormat.OpenXml.Packaging.SpreadsheetDocument.Open(Stream stream, Boolean isEditable)

Expected

I would expect there to be a Spreadsheet.OpenAsync or some similar mechanism to prevent blocking IO while loading the document.

@twsouthwick
Copy link
Member

twsouthwick commented Jan 6, 2022

We can't do anything directly here until System.IO.Packaging supports async calls. I believe there's a request somewhere for some async methods, but async-ifying the whole project will be a large endeavor that we'd need to catalog what APIs need it and what dependencies there are.

Kestrel

With Kestrel, you can enable sync io as an option:

services.Configure<KestrelServerOptions>(options =>
{
    options.AllowSynchronousIO = true;
});

or per controller:

HttpContext.Features.Get<IHttpBodyControlFeature>().AllowSynchronousIO = true;

Blazor components

Haven't explored this

Recommended workaround:

Unfortunately, you'll need to use a stream that supports sync operations for the foreseable future. Easiest way is to copy it to a MemoryStream.

@twsouthwick
Copy link
Member

For reference, even System.IO.Packaging is blocked by ZipArchive needing some async APIs. This is tracked at dotnet/runtime#1541 and is currently marked as P1 in .NET 7 compression work items at dotnet/runtime#62658

@twsouthwick
Copy link
Member

I'm going to close this as there's a workaround for the issue.

@riyasvp123
Copy link

Hi @twsouthwick

Could you please share the workaround. I am also facing the same issue.

@twsouthwick
Copy link
Member

I realize I made some assumptions here. Not only does the SDK require sync operations, it requires seeking, which is not available by default.

If this is for the response stream, then you'll need to ensure buffering as the response stream is not buffered but is sent to the client as soon as you start writing it. If it is for an incoming stream, you'll need to ensure it's fully read (although the AllowSyncIO flag may help here).

There's some functionality to enable this in https:/dotnet/systemweb-adapters and an issue to look at moving some of that functionality into ASP.NET Core proper.

For now, the relevant part would be something like https:/dotnet/systemweb-adapters/blob/main/src/Microsoft.AspNetCore.SystemWebAdapters.CoreServices/BufferResponseStreamMiddleware.cs. The attribute is metadata that can be added to endpoints or controllers (as an attribute) that will "turn on" the buffering so you can write to the stream. Hopefully for ASP.NET Core 8 it will be in-box so you don't need your own (or you can use the adapters, which should be v1 soon)

@riyasvp123
Copy link

@twsouthwick Thank you so much

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants