-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Description
[Breaking change]: ZipArchive.CrateAsync eagerly loads all zip archive entries, potentially throwing if central directory is malformed.
Description
Starting in .NET 11 Preview 1, the behavior of the System.IO.Compression.ZipArchive class has been updated to improve consistency in handling asynchronous streams. Specifically, in order to avoid synchronous reads on the stream when accessing .Entries property of ZipArchive, the list of entries is read during the CreateAsync method call. This change aligns with the approved API design and ensures that asynchronous operations are handled correctly.
Version
.NET 11 Preview 1
Previous behavior
Previously, when working with a ZipArchive created using CreateAsync, accessing the .Entries property could result in a synchronous (blocking) read operation being performed. This behavior was inconsistent with the asynchronous nature of the CreateAsync method.
Example:
using System.IO;
using System.IO.Compression;
using System.Threading.Tasks;
var stream = new FileStream("malformed.zip");
var archive = await ZipArchive.CreateAsync(stream, ZipArchiveMode.Read);
// This call performs synchronous reads on the stream, and may throw if the file entries in are malformed
// or if the underlying stream does not allow synchronous reads.
var entries = archive.Entries; New behavior
With the updated behavior, the central directory of the zip archive is read (asynchronously) as part of the ZipArchive.CreateAsync method. Any exceptions related to the inability to list the zip archive entries are now thrown during the CreateAsync method call. Later access to .Entries does not perform any read operations on the underlying stream.
Example:
using System.IO;
using System.IO.Compression;
using System.Threading.Tasks;
var stream = new MemoryStream();
// This call eagerly loads the zip archive entries, surfacing any exception when parsing the file headers.
var archive = await ZipArchive.CreateAsync(stream, ZipArchiveMode.Create, leaveOpen: true);
// Accessing `.Entries` no longer throws an exception, as the issue is surfaced during `CreateAsync`.
var entries = archive.Entries; // No exceptionType of breaking change
- Behavioral change: Existing binaries might behave differently at runtime.
Reason for change
This change was introduced to improve the consistency and reliability of the ZipArchive API when working with asynchronous streams. This aligns with the approved API design and avoids unexpected synchronous/blocking reads when accessing .Entries.
Recommended action
Developers should ensure that InvalidDataException thrown from ZipArchive.CreateAsync is correctly handled. This exception has already been thrown in previous .NET versions e.g. in cases when zip central directory cannot be found.
Affected APIs
System.IO.Compression.ZipArchive.CreateAsync(Stream, ZipArchiveMode, bool)System.IO.Compression.ZipArchive.Entries
Additional information
This change was introduced in dotnet/runtime#121938 and addresses issues raised in dotnet/runtime#121624. For more details on the API design discussion, see this comment.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status