Skip to content

fix!: read problem details without a serializer, move reflection to Refit.Reflection, drop deprecated .NET 8/9 - #2374

Merged
ChrisPulman merged 23 commits into
mainfrom
fix/problem-details-fast-path
Nov 3, 2026
Merged

ChrisPulman merged 23 commits into
mainfrom
fix/problem-details-fast-path

Conversation

@glennawatson

@glennawatson glennawatson commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

What kind of change does this PR introduce?

Bug fix (#2368), and removal of everything in the non-reflection packages that blocks the System.Text.Json fast path or uses reflection.

What is the new behavior?

  • ValidationApiException reads problem details with Refit's own JsonElement reader. No metadata, reflection or configured serializer needed ([Bug]: problem+json responses silently become a plain ApiException with source-generated JSON metadata or in a trimmed app #2368).
  • The default JSON options have no converters or NumberHandling. CamelCaseStringEnumConverter is gone and ProblemDetails.Extensions has no [JsonExtensionData]. For enum strings, set UseStringEnumConverter = true on your source-generated context.
  • Reflection moved to Refit.Reflection and the new Refit.HttpClientFactory.Reflection: RestService.For, RequestBuilder, AddRefitClient, AddKeyedRefitClient, ObjectToInferredTypesConverter, the method metadata types, and form and enum reflection.
  • IUrlParameterFormatter takes a Refit-owned IParameterAttributeProvider instead of ICustomAttributeProvider.
  • Generated form fields carry the serializer's field names, so Newtonsoft and XML bodies use the generated path.
  • Refit.Newtonsoft.Json and Refit.Xml are marked not trimmable and not AOT compatible.
  • net8.0 and net9.0 are dropped.

Breaking changes

  • Enums and numbers use System.Text.Json defaults (enums as numbers, no numbers-as-strings, object reads as JsonElement).
  • ValidationApiException ignores the configured serializer, and ProblemDetails.Extensions lost [JsonExtensionData].
  • Types listed above now live in the reflection packages. Reference Refit.Reflection (or Refit.HttpClientFactory.Reflection).
  • Generated-only apps with default settings must supply a source-generated context or call ReflectionSupport.EnsureRegistered().
  • IHttpContentSerializer.GetFieldNameForProperty is removed (use IReflectionFieldNameProvider).
  • Custom IUrlParameterFormatter implementations change their second parameter to IParameterAttributeProvider.
  • FormField<T> has a new constructor.
  • net8.0 and net9.0 are no longer targeted.

Closes #2368

- Read problem+json with Refit's own JsonElement reader, so it works with any resolver, when trimmed and under Native AOT

- Drop the default converters and number handling so the default options keep the System.Text.Json fast path

- Remove JsonExtensionData from ProblemDetails.Extensions and the unused ProblemDetailsJsonContext

- Move ObjectToInferredTypesConverter to Refit.Reflection and add AddReflectionConverters for opt-in enum names and inferred objects

Closes #2368

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
@codecov

codecov Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Codecov Report

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

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #2374   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          242       250    +8     
  Lines        13018     12949   -69     
  Branches      2416      2401   -15     
=========================================
- Hits         13018     12949   -69     

☔ View full report in Codecov by Harness.
📢 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.

- Move RestService.For and RequestBuilder to Refit.Reflection as extension members, keeping the call syntax

- Add Refit.HttpClientFactory.Reflection for AddRefitClient and AddKeyedRefitClient

- Make Refit.Testing use Refit.Reflection for CreateClient

- Drop net8.0 and net9.0 targets and their API baselines

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
@glennawatson glennawatson changed the title fix: read problem details without the configured serializer fix: read problem details without the configured serializer and move reflection out of core Nov 3, 2026
glennawatson and others added 11 commits November 3, 2026 17:02
- Remove RequiresUnreferencedCode and RequiresDynamicCode from IRequestBuilder and GeneratedOnlyRequestBuilder

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
- Add FormFieldNames and IContentSerializerNameStyle so generated form fields pick the right compile-time name

- Read Newtonsoft JsonProperty and XmlElement or XmlAttribute names in the generator

- Use the generated path for the Newtonsoft and Xml serializers, not just System.Text.Json

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
- Core flattens simple values, collections and dictionaries and calls a registered flattener only for run-time-typed complex values

- Move the property walk, its metadata cache and ReflectionPropertyHelpers to Refit.Reflection

- Add ReflectionSupport.EnsureRegistered, called by every reflection entry point

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
- Remove IHttpContentSerializer.GetFieldNameForProperty and the PropertyInfo hook from the System.Text.Json, Newtonsoft and Xml serializers

- Resolve names in Refit.Reflection from each serializer's name style, with IReflectionFieldNameProvider for custom serializers

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
- EnumHelpers keeps the numeric helpers; the run-time EnumMember attribute lookup is registered by Refit.Reflection

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
…tion

- RestMethodInfo, RestMethodParameterInfo and RestMethodParameterProperty are only produced by the reflection pipeline

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
…eflection

- The serializer always reads type metadata; options with no resolver get the reflection resolver Refit.Reflection registers, or a message explaining how to supply a context

- Remove the per-method reflection fallbacks, the polymorphism attribute checks and the trim suppressions

- StubHttp, the reflection request builder and RestService.For register the support

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
- Remove the Converters read from WritesDeclaredTypeAsObject so no production code touches a fast-path-blocking option

- Add converter and name-lookup tests for the types moved into Refit.Reflection

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
…compatible

- Remove the trim and AOT suppressions from the Newtonsoft and XML serializers, which wrap reflection-based libraries

- Cover the generator's named attribute argument parsing

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
…rovider in the formatter contract

- Add Refit-owned IParameterAttributeProvider so IUrlParameterFormatter no longer exposes System.Reflection
- Generated and core code pass an empty provider instead of a Type
- Wrap reflection elements in CachedAttributeProvider in Refit.Reflection
- Refresh public API baselines, snapshots, tests, examples and benchmarks

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
@glennawatson glennawatson changed the title fix: read problem details without the configured serializer and move reflection out of core fix!: read problem details without a serializer, move reflection to Refit.Reflection, drop deprecated .NET 8/9 Nov 3, 2026
glennawatson and others added 10 commits November 3, 2026 19:43
…tration

- Drop the emitted DynamicallyAccessedMemberTypes.All dependency and its polyfill
- Refresh snapshots and the test that asserted on it

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
- Add the rule to CLAUDE.md
- Drop an unused System.Reflection using from the Newtonsoft serializer

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
- Detect and copy modifiers of the reflection resolver through hooks registered by Refit.Reflection
- Replace the uncovered loop in FallbackExplanation with an index check
- Cover the unregistered hook paths

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
- Remove checks already implied by IsNullOrWhiteSpace and the earlier delay validation

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
- Remove the dead AllowRelative key check, as it is the attribute's only member

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
…ches

- Exclude two compiler-generated async finally edges and one unreachable BCL fallback
- Cover the retry ISO date with an empty value and the query string parser directly

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
- Cover generator edge cases: split partial interfaces, a missing Refit reference, three-argument returns and relative URLs on observables
- Cover the analyzer location and path helpers, async disposal and route binding branches
- Split the return type and delimiter classification into small testable helpers
- Exclude only compiler-generated async finally edges and an unreachable BCL fallback

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
- Register generated clients on .NET Framework by declaring ModuleInitializerAttribute when the target lacks it
- Assign the default JSON resolver under a lock so a shared serializer is thread safe
- Keep reflection registration out of the StubHttp constructor so AOT apps stay clean
- Drop the stale Refit.Reflection trimmer root and pack Refit.Reflection for the package consumer
- Update the ProblemDetails sample now that the metadata no longer fails

Co-authored-by: Atakan Ük <61142938+AtakanUk@users.noreply.github.com>
@sonarqubecloud

sonarqubecloud Bot commented Nov 3, 2026

Copy link
Copy Markdown

@ChrisPulman
ChrisPulman merged commit 89779cd into main Nov 3, 2026
30 checks passed
@ChrisPulman
ChrisPulman deleted the fix/problem-details-fast-path branch November 3, 2026 15:26
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.

[Bug]: problem+json responses silently become a plain ApiException with source-generated JSON metadata or in a trimmed app

2 participants