Skip to content

feat(IZipArchiveService): add ExtractToDirectoryAsync method#7272

Merged
ArgoZhang merged 6 commits intomainfrom
feat-arch
Dec 8, 2025
Merged

feat(IZipArchiveService): add ExtractToDirectoryAsync method#7272
ArgoZhang merged 6 commits intomainfrom
feat-arch

Conversation

@ArgoZhang
Copy link
Copy Markdown
Member

@ArgoZhang ArgoZhang commented Dec 8, 2025

Link issues

fixes #7271

Summary By Copilot

Regression?

  • Yes
  • No

Risk

  • High
  • Medium
  • Low

Verification

  • Manual (required)
  • Automated

Packaging changes reviewed?

  • Yes
  • No
  • N/A

☑️ Self Check before Merge

⚠️ Please check all items below before review. ⚠️

  • Doc is updated/provided or not needed
  • Demo is updated/provided or not needed
  • Merge the latest code from the main branch

Summary by Sourcery

Add asynchronous ZIP extraction support and extend archive directory options in the ZIP archive service.

New Features:

  • Introduce an asynchronous ExtractToDirectoryAsync method on IZipArchiveService and its default implementation for extracting archives without blocking.
  • Add an ArchiveDirectory overload that archives a mix of files and directories into a ZIP file.

Enhancements:

  • Update ArchiveAsync and ArchiveDirectory APIs to use clearer archiveFile parameter naming and leverage async ZipFile APIs where available via conditional compilation.

Copilot AI review requested due to automatic review settings December 8, 2025 05:30
@bb-auto bb-auto Bot added the enhancement New feature or request label Dec 8, 2025
@bb-auto bb-auto Bot added this to the v10.1.0 milestone Dec 8, 2025
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Dec 8, 2025

Reviewer's Guide

Adds asynchronous extraction support and more flexible archiving options to the zip archive service, updates method signatures and documentation, and introduces .NET 10 conditional async implementations while preserving backward compatibility.

Sequence diagram for ExtractToDirectoryAsync call flow

sequenceDiagram
    actor Caller
    participant ZipArchiveService as DefaultZipArchiveService
    participant ZipFileApi as ZipFile
    participant FileSystem

    Caller->>ZipArchiveService: ExtractToDirectoryAsync(archiveFile, destinationDirectoryName, overwriteFiles, encoding)
    activate ZipArchiveService
    ZipArchiveService->>FileSystem: Directory.Exists(destinationDirectoryName)
    alt destination does not exist
        ZipArchiveService->>FileSystem: Directory.CreateDirectory(destinationDirectoryName)
    end
    alt NET10_0_OR_GREATER
        ZipArchiveService->>ZipFileApi: ExtractToDirectoryAsync(archiveFile, destinationDirectoryName, encoding, overwriteFiles)
        Note right of ZipFileApi: await ZipFileApi
    else older_framework
        ZipArchiveService->>ZipFileApi: ExtractToDirectory(archiveFile, destinationDirectoryName, encoding, overwriteFiles)\nwrapped in Task.Run
        Note right of ZipFileApi: await ZipFileApi
    end
    ZipArchiveService-->>Caller: true
    deactivate ZipArchiveService
Loading

Class diagram for updated zip archive service API

classDiagram
    class IZipArchiveService {
        <<interface>>
        Task ArchiveAsync(archiveFile, files, options)
        Task ArchiveDirectory(archiveFile, directoryName, compressionLevel, includeBaseDirectory, encoding)
        Task ArchiveDirectory(archiveFile, entries, compressionLevel, encoding)
        bool ExtractToDirectory(archiveFile, destinationDirectoryName, overwriteFiles, encoding)
        Task bool ExtractToDirectoryAsync(archiveFile, destinationDirectoryName, overwriteFiles, encoding)
        Stream GetEntry(archiveFile, entryName, encoding)
    }

    class DefaultZipArchiveService {
        Task~Stream~ ArchiveAsync(files, options)
        Task ArchiveAsync(archiveFile, files, options)
        Task ArchiveDirectory(archiveFile, directoryName, compressionLevel, includeBaseDirectory, encoding)
        Task ArchiveDirectory(archiveFile, entries, compressionLevel, encoding)
        bool ExtractToDirectory(archiveFile, destinationDirectoryName, overwriteFiles, encoding)
        Task bool ExtractToDirectoryAsync(archiveFile, destinationDirectoryName, overwriteFiles, encoding)
        Stream GetEntry(archiveFile, entryName, encoding)
        static Task ArchiveFilesAsync(stream, files, options)
        static void AddFolderToZip(archive, folderPath, relativePath, compressionLevel)
    }

    IZipArchiveService <|.. DefaultZipArchiveService
Loading

File-Level Changes

Change Details Files
Extend zip archive service interface and default implementation with new async extraction method and overload for archiving mixed files/directories, using conditional async APIs where available.
  • Rename archive file parameters from archiveFileName to archiveFile in interface and implementation for consistency.
  • Modify ArchiveDirectory implementation to create the output folder if needed and call ZipFile.CreateFromDirectoryAsync on .NET 10, falling back to Task.Run with the sync API otherwise.
  • Add new ArchiveDirectory overload that accepts an enumerable of file and directory paths, recursively adding directories via a helper method and adding files as entries.
  • Introduce AddFolderToZip helper to walk directories recursively and add all files to the archive with relative paths preserved.
  • Add ExtractToDirectoryAsync method that ensures the destination directory exists and then uses ZipFile.ExtractToDirectoryAsync on .NET 10 or Task.Run with the sync API otherwise.
  • Declare corresponding new methods and updated parameter names on IZipArchiveService, ensuring the public contract matches the implementation.
src/BootstrapBlazor/Services/DefaultZipArchiveService.cs
src/BootstrapBlazor/Services/IZipArchiveService.cs

Assessment against linked issues

Issue Objective Addressed Explanation
#7271 Add an asynchronous ExtractToDirectoryAsync method to the IZipArchiveService interface with appropriate parameters for archive file, destination directory, overwrite behavior, and encoding.
#7271 Provide a concrete implementation of ExtractToDirectoryAsync in DefaultZipArchiveService that performs asynchronous extraction (using ZipFile.ExtractToDirectoryAsync when available, or a suitable async wrapper otherwise).

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

sourcery-ai[bot]
sourcery-ai Bot previously approved these changes Dec 8, 2025
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • In ArchiveDirectory(string archiveFile, IEnumerable<string> entries, ...), AddFolderToZip builds entry names with Path.Combine, which can introduce OS-specific path separators into ZIP entries; consider normalizing to '/' in the archive paths to ensure consistent cross-platform behavior.
  • For the pre-NET10_0 branches in ArchiveDirectory and ExtractToDirectoryAsync, the use of Task.Run around ZipFile APIs can consume thread-pool threads for long-running I/O; if these methods are called at scale, you may want to consider a non-Task.Run approach or a dedicated background scheduler to avoid potential thread starvation.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `ArchiveDirectory(string archiveFile, IEnumerable<string> entries, ...)`, `AddFolderToZip` builds entry names with `Path.Combine`, which can introduce OS-specific path separators into ZIP entries; consider normalizing to `'/`' in the archive paths to ensure consistent cross-platform behavior.
- For the pre-NET10_0 branches in `ArchiveDirectory` and `ExtractToDirectoryAsync`, the use of `Task.Run` around `ZipFile` APIs can consume thread-pool threads for long-running I/O; if these methods are called at scale, you may want to consider a non-`Task.Run` approach or a dedicated background scheduler to avoid potential thread starvation.

## Individual Comments

### Comment 1
<location> `src/BootstrapBlazor/Services/DefaultZipArchiveService.cs:116-118` </location>
<code_context>
+        // 添加当前文件夹中的所有文件
+        foreach (string filePath in Directory.GetFiles(folderPath))
+        {
+            string entryName = Path.Combine(relativePath, Path.GetFileName(filePath));
+            archive.CreateEntryFromFile(filePath, entryName, compressionLevel);
+        }
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Using `Path.Combine` for ZIP entry names may introduce platform-specific separators into the archive.

ZIP entries should use `/` as the directory separator, but `Path.Combine` uses the OS-specific separator (e.g., `\` on Windows), which can reduce cross-platform compatibility with other tools. Instead, construct the entry name with `'/'` (for example, `relativePath + "/" + Path.GetFileName(filePath)` or `string.Join('/', ...)`) so the archive remains portable.

```suggestion
        // 添加当前文件夹中的所有文件
        foreach (string filePath in Directory.GetFiles(folderPath))
        {
            var fileName = Path.GetFileName(filePath);
            var entryName = string.IsNullOrEmpty(relativePath)
                ? fileName
                : $"{relativePath}/{fileName}";

            archive.CreateEntryFromFile(filePath, entryName, compressionLevel);
        }
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/BootstrapBlazor/Services/DefaultZipArchiveService.cs
@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 8, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (2e41fc0) to head (1cb3175).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #7272   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          745       745           
  Lines        32586     32621   +35     
  Branches      4516      4522    +6     
=========================================
+ Hits         32586     32621   +35     
Flag Coverage Δ
BB 100.00% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an asynchronous ExtractToDirectoryAsync method to the IZipArchiveService interface and its implementation, along with a new ArchiveDirectory overload that accepts a collection of file/directory entries. The PR also standardizes parameter naming by renaming archiveFileName to archiveFile across the interface and implementation, and updates the package version from beta to release.

  • Adds ExtractToDirectoryAsync method with .NET 9+ optimization
  • Introduces ArchiveDirectory overload for archiving multiple entries
  • Standardizes parameter naming from archiveFileName to archiveFile

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 8 comments.

File Description
src/BootstrapBlazor/Services/IZipArchiveService.cs Adds interface definition for ExtractToDirectoryAsync and new ArchiveDirectory overload; renames parameters for consistency
src/BootstrapBlazor/Services/DefaultZipArchiveService.cs Implements new async extraction method with conditional compilation for .NET 9+; implements new archive overload with helper method for recursive folder processing
src/BootstrapBlazor/BootstrapBlazor.csproj Updates package version from 10.1.2-beta01 to 10.1.2 release

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/BootstrapBlazor/Services/DefaultZipArchiveService.cs Outdated
Comment thread src/BootstrapBlazor/Services/DefaultZipArchiveService.cs Outdated
Comment thread src/BootstrapBlazor/Services/DefaultZipArchiveService.cs
Comment thread src/BootstrapBlazor/Services/IZipArchiveService.cs
Comment thread src/BootstrapBlazor/Services/DefaultZipArchiveService.cs
Comment thread src/BootstrapBlazor/Services/DefaultZipArchiveService.cs
Comment thread src/BootstrapBlazor/Services/DefaultZipArchiveService.cs Outdated
Comment thread src/BootstrapBlazor/Services/DefaultZipArchiveService.cs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(IZipArchiveService): add ExtractToDirectoryAsync method

2 participants