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

Creating a ZIP is incompatible with ASP.NET asynchronous I/O #102450

Open
branko-d opened this issue May 20, 2024 · 4 comments
Open

Creating a ZIP is incompatible with ASP.NET asynchronous I/O #102450

branko-d opened this issue May 20, 2024 · 4 comments
Labels
area-System.IO.Compression untriaged New issue has not been triaged by the area owner

Comments

@branko-d
Copy link

Description

When trying construct a ZipArchive "on the fly" and serve it from the Web API, I have to turn-on the ASP.NET synchronous I/O mode, otherwise I get an exception when trying to create or write to ZIP entries. So far, I have encountered exceptions:

  • when calling Stream.WriteAsync on the stream returned from ZipArchiveEntry.Open,
  • and when calling ZipArchive.CreateEntry repeatedly (see the attached project).

Reproduction Steps

The following controller action illustrates the problem:

[HttpGet]
public async Task Get() {

    using (var zip_archive = new ZipArchive(Response.Body, ZipArchiveMode.Create, true)) {

        var zip_entry = zip_archive.CreateEntry("test.txt");

        await using (var stream = zip_entry.Open()) {
            // System.InvalidOperationException: 'Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.'
            await stream.WriteAsync(Encoding.UTF8.GetBytes("Hello ZIP!"));
        }

    }

}

Here is a small project which illustrates the problem:

ZipAspAsyncIO.zip

If you access the route /zip or /zip2 you'll see the exception in the debugger and the corresponding diagnostic page in the browser.

Expected behavior

The ZIP archive is constructed and served without throwing any exceptions.

Actual behavior

The following exception is thrown:

System.InvalidOperationException: 'Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.'

Regression?

No response

Known Workarounds

The exception can be avoided by setting IHttpBodyControlFeature.AllowSynchronousIO, as mentioned in aspnetcore / #7644.

That, of course, allows the ZIP code to "hog" the thread. It would be much better to upgrade the ZIP code to support true asynchronous I/O, which would benefit scalability and also remove the need for this workaround.

Configuration

.NET 8
Windows 11 Pro
x64

Other information

No response

@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label May 20, 2024
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-io-compression
See info in area-owners.md if you want to be subscribed.

@KeterSCP
Copy link

See #1560. As mentioned in linked issue, you can use Response.BodyWriter.AsStream() instead of Response.Body as a workaround.

@ericstj
Copy link
Member

ericstj commented May 21, 2024

This exception is originating from the backing stream you're passing to ZipArchive. So I guess the bug here is that ZipArchive has no way of knowing that the backing stream requires Async calls and Zip internally uses synchronous calls to write parts of the archive.

Changes here would probably be a feature request for new API that indicates how Zip should interact with the backing stream. I think for now you're better to use workaround listed - or use a different stream to write to.

@branko-d
Copy link
Author

So I guess the bug here is that ZipArchive has no way of knowing that the backing stream requires Async calls and Zip internally uses synchronous calls to write parts of the archive.

I'm calling WriteAsync on the stream returned from ZipArchiveEntry.Open. Shouldn't that be enough for Zip to "know" that it should use asynchronous calls internally?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.IO.Compression untriaged New issue has not been triaged by the area owner
Projects
None yet
Development

No branches or pull requests

3 participants