Skip to content

v5.0.0: System.Text.Json default, remove Newtonsoft, trusted publishing#17

Merged
Mako88 merged 4 commits into
mainfrom
v5-system-text-json
May 30, 2026
Merged

v5.0.0: System.Text.Json default, remove Newtonsoft, trusted publishing#17
Mako88 merged 4 commits into
mainfrom
v5-system-text-json

Conversation

@Mako88

@Mako88 Mako88 commented May 30, 2026

Copy link
Copy Markdown
Owner

Summary

Major release. Moves the default JSON serializer from Newtonsoft.Json to System.Text.Json, removes the Newtonsoft.Json dependency entirely, and switches the release workflow to NuGet trusted publishing (OIDC) so we no longer rely on a long-lived API key.

This is the breaking follow-up to 4.2.0, which added SimpleHttpSystemTextJsonSerializer as an opt-in.

Library changes (breaking)

  • SimpleHttpDefaultJsonSerializer now derives from SimpleHttpSystemTextJsonSerializer (System.Text.Json). The client's default serialization is now STJ. SimpleHttpSystemTextJsonSerializer is retained for callers who reference it explicitly.
  • Newtonsoft.Json PackageReference removed; System.Text.Json retained.
  • Version → 5.0.0 (csproj; the workflow computes the published version from the release:major label + latest tag).

Migration notes

System.Text.Json is stricter than Newtonsoft.Json. Watch for:

  • Non-public parameterless constructors — STJ won't use them; add a public ctor or [JsonConstructor].
  • Polymorphic/variable-shape fields — a field that's sometimes a string and sometimes an object throws under STJ where Newtonsoft coped.
  • Need the old behavior? Implement ISimpleHttpSerializer with a Newtonsoft serializer and set it on the client.

Tests

  • Converted the suite off Newtonsoft: JToken/JObjectSystem.Text.Json.Nodes, JsonConvertJsonSerializer.
  • The postman-echo data field is an empty string on form posts but an object on JSON posts — re-typed the test model field as JsonNode? so STJ accepts both (this surfaced the strictness difference above).
  • Default-serializer output test made line-ending agnostic (STJ newline differs by platform).
  • Green on net10.0 (85) and net48 (85).

Release workflow → trusted publishing

  • Added id-token: write permission.
  • Added a NuGet/login@v1 step that exchanges the OIDC token for a short-lived API key right before push; push now uses that key instead of secrets.NUGET_API_KEY.

⚠️ Required before merging (maintainer)

  1. On nuget.org → account → Trusted Publishing, add a policy: Repository Owner Mako88, Repository SimpleHttpClient, Workflow File release.yml, Environment empty.
  2. Add a repo secret NUGET_USER = your nuget.org username (profile name, not email).
  3. The old NUGET_API_KEY secret can be deleted afterward.

🤖 Generated with Claude Code

…nsoft

SimpleHttpDefaultJsonSerializer now derives from SimpleHttpSystemTextJsonSerializer
(System.Text.Json), so the client's default serialization moves off Newtonsoft.Json,
which is dropped as a dependency. Breaking: System.Text.Json is stricter — types using
a non-public parameterless constructor, or fields whose JSON shape varies (string vs
object), deserialize differently. README documents the migration.

Convert the test suite off Newtonsoft (JToken/JObject -> System.Text.Json.Nodes,
JsonConvert -> JsonSerializer). The postman-echo "data" field is an empty string on
form posts but an object on JSON posts; typed as JsonNode so STJ doesn't reject it.

Switch the release workflow to NuGet trusted publishing (OIDC) instead of a long-lived
API key: add id-token: write, exchange the token via NuGet/login@v1 right before push.
Requires a NUGET_USER secret and a trusted-publishing policy on nuget.org.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mako88 and others added 3 commits May 30, 2026 04:04
… gaps

The earlier fix typed PostmanEchoResponse.Data as JsonNode and read it via a
dynamic indexer, which defeated the test's purpose: verifying the serializer maps
JSON onto strongly-typed properties. Restore Data to the typed Args? and instead
attach an EmptyStringTolerantConverter that maps postman-echo's empty-string "data"
(returned for form posts) to null, keeping the typed assertions intact.

Fill noticeable serializer gaps surfaced by the v5 switch:
- nested object + collection + enum round-trip
- enums serialize as numbers (Newtonsoft parity)
- deserializing into a type with only a non-public constructor throws (the documented
  System.Text.Json strictness difference)
- the default serializer is System.Text.Json-backed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Soften the default System.Text.Json options to ease the v5 migration without
masking genuine type errors:
- NumberHandling = AllowReadingFromString (quoted numbers bind to numeric props)
- AllowTrailingCommas = true
- ReadCommentHandling = Skip

Deliberately not softened: non-public constructors and wrong-shape coercion stay
strict (documented, with a custom-converter escape hatch in the README). Add tests
for the new leniencies.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cover the previously-untested provider stack: the factory returns the right
provider per target framework, GetClient returns a configured client cached across
calls (no factory) or delegates to the IHttpClientFactory (with one), and Dispose
disposes the owned client and is idempotent. Add InternalsVisibleTo for the test
assembly so the internal providers/factory can be exercised directly.

The net10.0 run exercises PooledHttpClientProvider; net48 exercises
RotatingHttpClientProvider. Timer-driven rotation (5-min interval) is left untested
as it has no injectable seam.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@Mako88 Mako88 left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

I attempted to approve this, but GitHub rejected it because the PR author and reviewer are the same account. For the record, after reviewing the diff I did not find any blocking issues.

Highlights from the review:

  • The v5 breaking change is clearly documented and appropriately scoped for a major release.
  • SimpleHttpDefaultJsonSerializer now delegates to the System.Text.Json implementation while preserving the public type, which minimizes migration friction.
  • The migration notes correctly call out the biggest Newtonsoft → STJ behavior differences.
  • Test coverage was expanded around the new serializer behavior (quoted numbers, comments/trailing commas, enum serialization, non-public constructors, etc.).
  • The trusted publishing workflow change looks sound and removes reliance on a long-lived API key.
  • CI is green on the current head commit.

Only minor observation: InternalsVisibleTo was added to test internal provider selection. That's reasonable, though it does create some coupling between tests and implementation details. Not a blocker.

If I were reviewing this as a separate GitHub user, this would be an approval from me.

@Mako88 Mako88 merged commit 516b213 into main May 30, 2026
2 checks passed
@Mako88 Mako88 deleted the v5-system-text-json branch May 30, 2026 09:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant