Modify System.IO.Packaging files to ensure they are deterministic. Helpful for testing, build reproducibility, security verification, and ensuring package integrity across different build environments.
Example file formats that leverage System.IO.Packaging
- .nupkg
- Microsoft Office files
See Milestones for release notes.
- For an input package stream
- Duplicate each entry with Deflate compression and consistent order
- Omit
package/services/metadata/core-properties/*.psmdcpentries - Omit
.signature.p7sentries (NuGet package signatures are invalidated by the conversion since package contents are modified) - For all relationship entries (
.relsfiles)- Modify the
Idof eachRelationshipto be deterministic - Convert absolute
Targetpaths to relative (e.g.Target="/xl/workbook.xml"becomesTarget="xl/workbook.xml") - Order
Relationships byType
- Modify the
- For the relationships entry
_rels/.rels- Remove the
Relationshipfor the.psmdcpentry
- Remove the
- For the relationships entry
docProps/core.xml- Remove the
creator,created,lastModifiedBy, andmodifiedelements
- Remove the
The conversion throws if any spreadsheetml XML entry (e.g. xl/workbook.xml, xl/worksheets/sheet1.xml) uses a prefixed default namespace such as <x:worksheet xmlns:x="..."> instead of the unprefixed form <worksheet xmlns="...">. This is because tools like Microsoft Spreadsheet Compare cannot open files with prefixed spreadsheetml elements. The OpenXml SDK can produce this form — ensure source xlsx files use default namespace declarations.
Binary output may differ between .NET Framework (net48) and .NET (net10.0+) due to differences in Deflate compression implementations. The XML content within entries is identical — only the compressed bytes differ.
This applies to all package formats (xlsx, docx, nupkg, etc.). When snapshot-testing binary package output across multiple target frameworks using Verify, use UniqueForRuntime to generate framework-specific verified files:
await Verify(stream, extension: "xlsx")
.UniqueForRuntime();See Verify Naming docs for more details.
using var sourceStream = File.OpenRead(packagePath);
await DeterministicPackage.ConvertAsync(sourceStream, targetStream);using var sourceStream = File.OpenRead(packagePath);
await DeterministicPackage.ConvertAsync(sourceStream, targetStream);Pi designed by Zaidan from The Noun Project.