Refit 14.0.0
Refit 14 is a major bug-fix and request-generation release. It fixes a broad set of correctness issues while completing the move to source-generated request building. Most clients can now build requests without runtime reflection, improving trimming, Native AOT support, startup time, and allocations.
What end users need to know
- Check RF006 warnings before upgrading. The reflection request builder has moved out of the main package. If any API method reports RF006, add the
Refit.Reflectionpackage. Fully generated clients should not add it. - Some async APIs now return
ValueTask. This affects the success-guard methods,DefaultApiExceptionFactory.CreateAsync, and severalRefitSettingsdelegates. Most callers can continue toawaitthem; code that stores aTaskmay need.AsTask(). - A few request-building behaviours are intentionally different. Query objects are flattened from their declared type, serializer property names are honoured in query keys, and nested URL-encoded objects are flattened instead of using
ToString(). - Caller-owned streams remain open. Refit no longer disposes streams supplied as request bodies or multipart parts; callers are responsible for disposing them.
- Validation timing can change. Fully generated interfaces validate route templates when the first request is built rather than when the client is created. Generated method frames also no longer appear in
ApiExceptionstack traces. - Empty authorization tokens now omit the header. Returning null, empty, or whitespace from
AuthorizationHeaderValueGetterno longer sends a blankAuthorizationheader.
Major fixes
- Request generation now handles multiple generic overloads, escaped C# keyword identifiers, nullable value-type query objects, nested URL-encoded bodies, and indexed query collections correctly.
- Caller-supplied request streams can be reused, generated helper types no longer collide across
InternalsVisibleToassemblies, and null parameter values round-trip correctly.
Highlights
- New request controls include
[PathPrefix], per-method[Timeout], absolute URLs with[Url], optional route segments, indexed query collections, header validation, and returning a builtHttpRequestMessagewithout sending it. - Query objects, dictionaries, generic methods, multipart form objects, and custom return-type adapters gain broader reflection-free generation.
- Server-Sent Events can be consumed as
IAsyncEnumerable<T>, and transport exceptions can be customized withTransportExceptionFactory. - Runtime, reflection, and source-generator allocation reductions improve throughput; source generation is roughly twice as fast in the measured workload.
See the V14 migration details and complete feature documentation.
๐๏ธ What's Changed
๐ฅ Breaking Changes
- e511df2 feat!: reflection-free source-generated request building (#2210) @glennawatson @TimothyMakkison
โจ Features
- 88e1c24 feat: add generic tests to
ReflectionTests(#2195) @TimothyMakkison - 463f5cf feat: add [Timeout] attribute for per-method request timeouts (#2238) @glennawatson
- 294e63a feat: add success guards to the non-generic IApiResponse (#2242) @glennawatson
- f754684 feat: add interface-level [PathPrefix] attribute for a shared route prefix (#2240) @glennawatson
- 65f864e feat: only generate
AttributeProviderfield when not empty (#2271) @TimothyMakkison - 99c055b feat: support optional url segments with {name?} syntax (#2237) @glennawatson
- 759a3c0 feat: support returning the built HttpRequestMessage without sending (#2235) @glennawatson
- 88d5e68 feat: add CollectionFormat.Indexed for indexed query collection expansion (#2262) @Copilot @glennawatson @jgarciadelanoceda
- d9b3d5f feat: support Server-Sent Events as a streaming content format (#2232) @glennawatson
- 1e35cc9 feat: add [Url] attribute for absolute request URLs (#2236) @glennawatson
- 7c33871 feat: add opt-in RefitSettings.ValidateHeaders (#2225) @glennawatson
- b583a34 feat: add null handling for round trip parameter and add verifying test (#2201) @TimothyMakkison
- 485c632 feat: opt-in [FormObject] flattens a model into multipart form fields (#2245) @glennawatson
- 7ac3e1a feat: fix failiure when multiple generic overloads (#2199) @TimothyMakkison
- 852cb2c feat: move version configuration into
AddConfiguredRequestOptions(#2214) @glennawatson @TimothyMakkison - a2b1581 feat: add analyzer diagnostics for invalid Refit interfaces (#2220) @glennawatson
- 4068d97 feature: Create a TransportExceptionFactory to let the user decide the exception to be thrown (#2205) @glennawatson @jgarciadelanoceda
- ed63528 feat: optional auth header and scoped authorization token provider (#2221) @glennawatson
- 7bf7b41 feat: inline constrained-generic path-bound objects in the source generator (#2222) @glennawatson
- 14895a4 feat: expose call argument values to DelegatingHandlers (#2223) @glennawatson
- 37efb4e feat: add per-type URL parameter formatter registry (#2226) @glennawatson
- aa1c19b feat: publish method name and route template in request options (#2239) @glennawatson
โป๏ธ Refactoring
- aa2229b refactor: resolve analyzer diagnostics across solution (#2268) @ChrisPulman
๐ Fixes
- 8e4237b fix:Analyzer false positive on Indexed CollectionFormat (#2274) @jgarciadelanoceda
- 809de10 fix: do not dispose caller-supplied request streams (#2234) @glennawatson
- 71634f2 fix: escape keyword identifiers in generated interface member names (#2248) @glennawatson
- 17c24d8 fix: name generated helper types per assembly to avoid InternalsVisibleTo conflicts (#2257) @glennawatson
- 78271e1 fix: generate inline query building for nullable value-type query objects (#2265) @rmja
- 02a037b fix: flatten nested objects in url-encoded request bodies (#2224) @glennawatson
โก Performance
- 147282a perf: replace
StringBuilderwithValueStringBuilderinRoundTripEscapePath(#2253) @TimothyMakkison - b193498 perf: replace
StringBuilderwithValueStringBuilder(#2270) @TimothyMakkison - eb92914 perf: call
PooledStringBuilderdirectly and removeConcatPartsandJoinParts(#2275) @TimothyMakkison - b575c9d perf:
AllAttributesCachereplaceLazywith laziliy initialised code (#2211) @TimothyMakkison - 8382bed perf: reduce Refit.Reflection memory allocations (#2267) @glennawatson
- fc06c57 perf: check for
allowUnmatchedParameterbefore callingIndexOf(#2252) @TimothyMakkison - f24d171 perf: wrap helper methods in
MethodImplOptions.AggressiveInlining(#2260) @TimothyMakkison - 8cea3f1 perf: reduce runtime Refit memory allocations (#2263) @glennawatson
- 5dcfcc9 perf: cut source generator allocations and roughly halve generation time (#2259) @glennawatson
๐งน General Changes
- 44f81de ci: gate native AOT smoke test via shared reusable workflow (#2244) @glennawatson
- a9932f8 chore: enable 1000 lines for real @glennawatson
- 393b245 ci: add alpha/beta/rc pre-release channel to release workflow @glennawatson
- 8cc1c37 chore: Relax number of file lines to 1000 lines instead of 500 @glennawatson
โ Tests
- e5da8b8 test: reach 100% product code coverage (#2243) @glennawatson
- 865d0f2 test(refit.testing): cover retry and timeout scenarios (#2208) @glennawatson
- e67c5c4 test: cover TransportExceptionFactory cancellation and timeout behavior (#2203) @arpitjain099 @glennawatson
๐ Documentation
- 544db0b docs: make v12 Error.Content migration discoverable and add interface composition example (#2217) @glennawatson
- 69eb3ee docs: document IQueryConverter and httpClientName client-name override (#2233) @glennawatson
๐ฆ Dependencies
- Combined package, analyzer, and workflow dependency updates: NuGet dependencies and analyzers (3d0546d, ddc42c9, 5cd9a96); Verify.DiffPlex 3.3.1 (841ff03); Verify.TUnit 31.24.2, 31.24.3, 31.25.0, and 31.27.0 (136d002, e1512d1, fb87be5, cf77d87); actions/setup-dotnet v6 (b920e21); and the lock-threads workflow action (d688b1f).
๐ Full Changelog: v13.1.0...v14.0.0
๐ Contributions
๐ฑ New contributors since the last release: @arpitjain099, @jgarciadelanoceda, @rmja
๐ Thanks to all the contributors: @arpitjain099, @ChrisPulman, @Copilot, @glennawatson, @jgarciadelanoceda, @rmja, @TimothyMakkison
๐ค Automated services that contributed: @renovate[bot]