Skip to content

Add Native AOT support and replace Newtonsoft.Json with System.Text.Json - #82

Open
chrisbbe wants to merge 1 commit into
ChangemakerStudios:developfrom
chrisbbe:AOT-compatibility
Open

chrisbbe wants to merge 1 commit into
ChangemakerStudios:developfrom
chrisbbe:AOT-compatibility

Conversation

@chrisbbe

@chrisbbe chrisbbe commented Oct 1, 2026 •

Copy link
Copy Markdown

Make the client usable in trimmed and Native AOT apps. The package is now marked IsAotCompatible for .NET 8 and newer and builds without trim or AOT warnings.

Library

  • Remove the Newtonsoft.Json dependency. Cookies, bookmarks and simple maps go through a source-generated JsonSerializerContext; loosely typed values (metadata, overlay options, extra headers) are written by JsonObjectWriter, which inspects runtime types instead of reflecting.
  • Annotate FacetBase with DynamicallyAccessedMembers so the [MultiFormHeader] properties survive trimming.
  • Rewrite GotenbergApiException.ToVerboseJson with Utf8JsonWriter.
  • Replace the [Description] reflection lookup for dimension units with a switch, and use the generic Enum.GetValues on .NET 5+.
  • Reference System.Text.Json 8.0.5 on the netstandard targets.

Breaking changes

  • JObject is gone from the public API. PdfOutputOptions.MetaData, WriteMetadataRequest.Metadata, WatermarkOptions.Options, StampOptions.Options and HtmlConversionBehaviors.ExtraHeaders are now IDictionary<string, object>; builder overloads take that or a System.Text.Json.Nodes.JsonObject.
  • Dictionary values must be primitives, dates, byte arrays, dictionaries, collections or JsonNode/JsonElement. Other object types throw NotSupportedException when passed to the builder.
  • Builders copy the supplied dictionary (shallow).
  • ReadPdfBookmarksAsync throws System.Text.Json.JsonException on malformed JSON; an empty body returns no bookmarks.
  • ToVerboseJson writes a fixed set of fields, and JSON form fields are sent compact rather than indented.

Tests and CI

  • Add test/GotenbergSharpClient.AotSmokeTest, a Native AOT console app that exercises the client against an in-process stub and, when GOTENBERG_URL is set, a live Gotenberg. Trim and AOT warnings fail its publish.
  • Publish and run the smoke test in deploy.yml before Pack.
  • Move the test projects, examples and CI to .NET 10.
  • Convert test assertions to System.Text.Json.Nodes and add JsonValueHandlingTests for the new value handling.

Examples and docs

  • Fix five examples that referenced namespaces removed in v3.0.0, and add all examples to the solution so CI builds them.
  • Correct the using statements in docs/getting-started.md.

Summary by CodeRabbit

  • New Features
    • Added support for Native AOT compilation and trimming, with new JSON handling that removes the Newtonsoft.Json dependency.
    • Metadata, headers, watermark, and stamp options now accept dictionaries or JsonObject. Unsupported dictionary value types throw an exception.
    • Added examples covering PDF operations and Chromium features.
  • Bug Fixes
    • Empty or whitespace-only bookmark responses now return no bookmarks; malformed JSON still raises an error.
  • Breaking Changes
    • Public JSON-related APIs now use dictionaries or JsonObject instead of JObject.
    • Verbose error JSON includes selected request and response details rather than reflecting over underlying objects.

Make the client usable in trimmed and Native AOT apps. The package is
now marked IsAotCompatible for .NET 8 and newer and builds without trim
or AOT warnings.

Library
- Remove the Newtonsoft.Json dependency. Cookies, bookmarks and simple
  maps go through a source-generated JsonSerializerContext; loosely
  typed values (metadata, overlay options, extra headers) are written by
  JsonObjectWriter, which inspects runtime types instead of reflecting.
- Annotate FacetBase with DynamicallyAccessedMembers so the
  [MultiFormHeader] properties survive trimming.
- Rewrite GotenbergApiException.ToVerboseJson with Utf8JsonWriter.
- Replace the [Description] reflection lookup for dimension units with
  a switch, and use the generic Enum.GetValues on .NET 5+.
- Reference System.Text.Json 8.0.5 on the netstandard targets.

Breaking changes
- JObject is gone from the public API. PdfOutputOptions.MetaData,
  WriteMetadataRequest.Metadata, WatermarkOptions.Options,
  StampOptions.Options and HtmlConversionBehaviors.ExtraHeaders are now
  IDictionary<string, object>; builder overloads take that or a
  System.Text.Json.Nodes.JsonObject.
- Dictionary values must be primitives, dates, byte arrays,
  dictionaries, collections or JsonNode/JsonElement. Other object types
  throw NotSupportedException when passed to the builder.
- Builders copy the supplied dictionary (shallow).
- ReadPdfBookmarksAsync throws System.Text.Json.JsonException on
  malformed JSON; an empty body returns no bookmarks.
- ToVerboseJson writes a fixed set of fields, and JSON form fields are
  sent compact rather than indented.

Tests and CI
- Add test/GotenbergSharpClient.AotSmokeTest, a Native AOT console app
  that exercises the client against an in-process stub and, when
  GOTENBERG_URL is set, a live Gotenberg. Trim and AOT warnings fail its
  publish.
- Publish and run the smoke test in deploy.yml before Pack.
- Move the test projects, examples and CI to .NET 10.
- Convert test assertions to System.Text.Json.Nodes and add
  JsonValueHandlingTests for the new value handling.

Examples and docs
- Fix five examples that referenced namespaces removed in v3.0.0, and
  add all examples to the solution so CI builds them.
- Correct the using statements in docs/getting-started.md.
@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 18fa4a1a-b830-413b-83f0-75c0d1d133c8

📥 Commits

Reviewing files that changed from the base of the PR and between b3998d7 and a9c0c3b.

📒 Files selected for processing (49)
  • .github/workflows/deploy.yml
  • CHANGES.MD
  • GotenbergSharpApiClient.sln
  • docs/getting-started.md
  • examples/ChromiumFeatures/Program.cs
  • examples/Directory.Build.props
  • examples/EncryptPdf/Program.cs
  • examples/LibreOfficeOptions/Program.cs
  • examples/PdfEngineOperations/Program.cs
  • examples/Screenshot/Program.cs
  • examples/WatermarkAndRotate/Program.cs
  • src/Gotenberg.Sharp.Api.Client/Application/Builders/PdfEngineBuilder.cs
  • src/Gotenberg.Sharp.Api.Client/Application/HtmlBehavior/HtmlConversionBehaviorBuilder.cs
  • src/Gotenberg.Sharp.Api.Client/Application/Overlays/StampOptionsBuilder.cs
  • src/Gotenberg.Sharp.Api.Client/Application/Overlays/WatermarkOptionsBuilder.cs
  • src/Gotenberg.Sharp.Api.Client/Application/PdfOutput/PdfOutputOptionsBuilder.cs
  • src/Gotenberg.Sharp.Api.Client/Domain/Bookmarks/Bookmark.cs
  • src/Gotenberg.Sharp.Api.Client/Domain/Bookmarks/BookmarkSet.cs
  • src/Gotenberg.Sharp.Api.Client/Domain/Cookies/Cookie.cs
  • src/Gotenberg.Sharp.Api.Client/Domain/Dimensions/Dimension.cs
  • src/Gotenberg.Sharp.Api.Client/Domain/ExtraHeaders/ExtraHttpHeaders.cs
  • src/Gotenberg.Sharp.Api.Client/Domain/ExtraUrls/ExtraUrlResourceItem.cs
  • src/Gotenberg.Sharp.Api.Client/Domain/HtmlBehavior/EmulatedMediaFeature.cs
  • src/Gotenberg.Sharp.Api.Client/Domain/HtmlBehavior/HtmlConversionBehaviors.cs
  • src/Gotenberg.Sharp.Api.Client/Domain/Overlays/StampOptions.cs
  • src/Gotenberg.Sharp.Api.Client/Domain/Overlays/WatermarkOptions.cs
  • src/Gotenberg.Sharp.Api.Client/Domain/PdfOutput/PdfOutputOptions.cs
  • src/Gotenberg.Sharp.Api.Client/Domain/Requests/EmbedRequest.cs
  • src/Gotenberg.Sharp.Api.Client/Domain/Requests/FacetBase.cs
  • src/Gotenberg.Sharp.Api.Client/Domain/Requests/WriteMetadataRequest.cs
  • src/Gotenberg.Sharp.Api.Client/Extensions/EnumExtensions.cs
  • src/Gotenberg.Sharp.Api.Client/GlobalUsings.cs
  • src/Gotenberg.Sharp.Api.Client/Gotenberg.Sharp.Api.Client.csproj
  • src/Gotenberg.Sharp.Api.Client/GotenbergSharpClient.cs
  • src/Gotenberg.Sharp.Api.Client/Infrastructure/DynamicallyAccessedMembersAttribute.cs
  • src/Gotenberg.Sharp.Api.Client/Infrastructure/GotenbergApiException.cs
  • src/Gotenberg.Sharp.Api.Client/Infrastructure/Json/GotenbergJsonContext.cs
  • src/Gotenberg.Sharp.Api.Client/Infrastructure/Json/JsonObjectWriter.cs
  • src/Gotenberg.Sharp.Api.Client/Infrastructure/MultiFormPropertyItem.cs
  • test/GotenbergSharpClient.AotSmokeTest/GotenbergSharpClient.AotSmokeTest.csproj
  • test/GotenbergSharpClient.AotSmokeTest/Program.cs
  • test/GotenbergSharpClient.Tests/BookmarkTests.cs
  • test/GotenbergSharpClient.Tests/ChromiumMissingFieldsTests.cs
  • test/GotenbergSharpClient.Tests/CookieTests.cs
  • test/GotenbergSharpClient.Tests/GotenbergSharpClient.Tests.csproj
  • test/GotenbergSharpClient.Tests/HtmlConversionBehaviorBuilderTests.cs
  • test/GotenbergSharpClient.Tests/JsonValueHandlingTests.cs
  • test/GotenbergSharpClient.Tests/PdfEngineOperationsTests.cs
  • test/GotenbergSharpClient.Tests/ValueObjects/EmulatedMediaFeatureTests.cs

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.


📝 Walkthrough

Walkthrough

The client replaces Newtonsoft.Json with System.Text.Json and source-generated serialization. JSON-facing builder and model APIs change to dictionaries or JsonObject. The pull request also adds Native AOT smoke tests, updates examples and documentation, and moves the workflow and example projects to .NET 10.

Changes

Client JSON and AOT changes

Layer / File(s) Summary
System.Text.Json foundation
src/Gotenberg.Sharp.Api.Client/Infrastructure/Json/*, src/Gotenberg.Sharp.Api.Client/GlobalUsings.cs, src/Gotenberg.Sharp.Api.Client/Gotenberg.Sharp.Api.Client.csproj
Adds source-generated serializer metadata and a JSON writer for supported loosely typed values. Replaces the Newtonsoft.Json dependency with System.Text.Json references for .NET Standard targets.
JSON APIs and request serialization
src/Gotenberg.Sharp.Api.Client/Application/*, src/Gotenberg.Sharp.Api.Client/Domain/*, src/Gotenberg.Sharp.Api.Client/Infrastructure/GotenbergApiException.cs, src/Gotenberg.Sharp.Api.Client/GotenbergSharpClient.cs, test/GotenbergSharpClient.Tests/*
Changes JSON inputs and properties from JObject to dictionaries or JsonObject. Updates model and request serialization, verbose exception JSON, and bookmark response handling. Updates related tests and adds coverage for supported values, snapshots, and bookmark response bodies.
Trimming annotations and AOT validation
src/Gotenberg.Sharp.Api.Client/Infrastructure/*, test/GotenbergSharpClient.AotSmokeTest/*, .github/workflows/deploy.yml, GotenbergSharpApiClient.sln, test/GotenbergSharpClient.Tests/GotenbergSharpClient.Tests.csproj
Adds trimming annotations and compatibility definitions. Adds a Native AOT smoke-test executable and runs its Linux x64 Release publish in the deployment workflow. Updates solution registrations and targets the test project to .NET 10.
Examples and release notes
CHANGES.MD, docs/getting-started.md, examples/*
Updates example imports and JSON parsing to use the revised namespaces and System.Text.Json. Targets examples to .NET 10, upgrades Microsoft.Extensions packages to 10.0.0, and documents the listed API and serialization changes.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~60 minutes

Change: Feature

Suggested reviewers: jaben

Merge Risk: ⚪ Minimal · up to a9c0c

The JSON migration shows no confirmed merge-blocking problem in the reviewed evidence. Normal CI and the AOT smoke test remain the final checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to a9c0c

The checked request paths preserve the separation between browser headers and service authentication. Consumers must adapt to breaking JSON API changes and should not treat shallow dictionary copies as immutable requests. No introduced security vulnerability was established, but consumer and runtime coverage remains incomplete.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The changed serialization paths affect client-process request construction, data sent to the configured Gotenberg service, and browser headers supplied through Chromium conversion requests. No tenant-wide or environment-wide exposure can be established without consumer and deployment context.

Trust Boundaries and Controls

  • observed — The single-header overload replaces JSON string interpolation and parsing with dictionary construction. Utf8JsonWriter supplies structural escaping, while the relaxed encoder intentionally leaves HTML-sensitive characters unescaped; these request values are emitted as multipart JSON, not HTML.

Resilience and Maintainability Implications

  • observed — Snapshot validates an outer dictionary copy before assignment, preserving the previous option when initial validation fails. Nested collections, dictionaries, byte arrays, and JSON values remain shared and are traversed again during serialization. Unlike the prior dictionary metadata conversion through JObject.FromObject, this does not freeze the nested value graph.

Hardening Proposals

  • proposed — Consumers that transfer validated request data across trust boundaries should freeze or independently copy the complete JSON value graph. A shallow builder snapshot should not serve as an authorization or cross-tenant isolation boundary.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.52% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 81 functions across 41 files. (8 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the two main changes: Native AOT support and replacement of Newtonsoft.Json with System.Text.Json.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 18.52% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 81 functions across 41 files. (8 skipped: 8 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
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

Successfully merging this pull request may close these issues.

1 participant