Summary
Refit 16.4.0 adds opt-in HTTP-aware retries, new query naming and relative URL options, and fixes for parameter binding and response handling. Existing clients keep their current behavior unless you enable the new options.
HTTP-aware retries
HttpRetryHandler works with Refit clients and ordinary HttpClient calls. It needs no extra resilience package or changes to your API interface.
- By default, it allows three retries after the first send for GET, HEAD, OPTIONS and TRACE. It retries HTTP 408, 429, 500, 502, 503 and 504, plus
HttpRequestException. A 403 retries only when the configured delay reader finds a valid timing hint. - The default reader respects standard
Retry-Afterheaders.RetryDelayProviders.Azure,.Aws,.GitHuband.Jiraalso read provider-specific timing headers. Custom readers can useReadHeaderwith seconds, milliseconds, Unix timestamps or date formats. - When no valid hint is available, retries use exponential backoff starting at one second and capped at 30 seconds. Full jitter randomly spreads attempts within that interval. You can disable jitter or choose symmetric variation with
RetryJitterMode.Symmetric. - Server hints are never shortened by jitter. A hint above
MaxDelayreturns the response rather than retrying too early.ServerDelayJitterRatiocan add a small positive variation to a server delay. - Each attempt uses a fresh request with copied headers, options and content metadata. Request bodies are buffered once, with a one MiB default limit. Failed responses are disposed; the final response remains caller-owned. Cancellation covers buffering, sends and waits.
Quick start
Put the retry handler in the client's handler chain, then create your Refit client as usual:
using Refit;
var handler = new HttpRetryHandler(new HttpRetryOptions
{
MaxRetries = 3,
DelayProvider = RetryDelayProviders.GitHub,
})
{
InnerHandler = new HttpClientHandler(),
};
using var client = new HttpClient(handler)
{
BaseAddress = new Uri("https://api.github.com"),
};
var api = RestService.ForGenerated<IGitHubApi>(client);IGitHubApi is your existing Refit interface. Omit DelayProvider to use standard Retry-After handling. With Refit.HttpClientFactory, register a fresh handler for the client:
services.AddRefitGeneratedClient<IGitHubApi>()
.ConfigureHttpClient(static client =>
client.BaseAddress = new Uri("https://api.github.com"))
.AddHttpMessageHandler(static () => new HttpRetryHandler(new HttpRetryOptions
{
DelayProvider = RetryDelayProviders.GitHub,
}));Set MaxRetries = 0 to disable retries. Use ShouldRetry to replace the response rules, and BaseDelay / MaxDelay to tune waits. POST, PUT, PATCH and DELETE require RetryUnsafeMethods = true; enable this only when replay is safe for the endpoint, such as when it supports an idempotency key. Avoid unbounded streaming uploads and stacking this handler with another retry strategy.
An authentication handler inside the retry handler runs on every attempt. HttpClient.Timeout bounds the whole call, including retry waits. For deterministic tests, Refit.Testing adds RetryReply.After, RetryReply.Header and StubHttp.CreateRetryHandler, with TimeProvider support.
Other changes
[Query(Name = "client_id")]names a query parameter or form field.[AliasAs]still takes precedence. The positional[Query("...")]argument remains a nesting delimiter, not an alias; the new opt-in diagnostic RF016 helps catch that mistake.[Url(AllowRelative = true)]accepts relative as well as absolute URLs, using normal URI resolution againstHttpClient.BaseAddress. Existing encoded queries are retained when appending query parameters. Plain[Url]still requires an absolute URL.RefitSettingsnow groups options underSerialization,Url,ExceptionsandRequests. Existing top-level properties remain available and refer to the same settings. Retry options similarly exposeBackoff,ReplayandResponsesgroups.- The generator pipeline and model equality handling were reorganized, with added coverage for inherited interfaces, incremental generation and request construction.
- New tested documentation recipes cover resilience and OpenTelemetry. CI now publishes and runs a consumer of the packed Refit packages under Native AOT on Windows, Linux and macOS, as well as the documentation NativeClient.
- Dependency and build updates include ReactiveUI.Primitives 9 and refreshed test packages and GitHub Actions. Local Refit packages are excluded from Renovate updates.
Fixes
- Route and query parameters whose names differ only by case now bind correctly in generated and reflection-based clients. Exact-case route matches take priority, and sibling query parameters no longer overwrite route values. This also covers mixed ordinary and catch-all placeholders. (#2360)
IApiResponse.ContentHeaders.ContentLengthremains readable after response content is buffered or disposed, including when no explicitContent-Lengthheader was sent. (#2360)- If response buffering fails mid-stream and deserialization then fails because the stream was consumed, Refit surfaces the original buffering exception instead of the misleading deserialization error. Content that remains readable can still be deserialized. (#2360)
- Native AOT smoke publishing on .NET 11 RC2 no longer fails while trying to copy a missing XML documentation file. (#2360)
๐๏ธ What's Changed
โจ Features
- 57ab320 feat: add a Native AOT package consumer and resilience and telemetry recipes (#2342) @glennawatson
- 92ae878 feat(http): add header-aware retries (#2364) @glennawatson
๐ Fixes
- 8e03c5e fix: disambiguate case-differing parameters, preserve ContentLength header, and surface buffering exceptions (#2360) @glennawatson
๐งน General Changes
- 695344d ci: keep local Refit packages out of Renovate @glennawatson
- 970bf3e build: remove third-party analyzer packages (#2351) @glennawatson
๐ฆ Dependencies
- 7c2efd1 chore(deps): update dependency tunit to 1.69.16 (#2341) renovate[bot]
- db1db92 chore(deps): update dependency reactiveui.primitives to v9 (#2350) renovate[bot]
- fbf8edd chore(deps): update dependency tunit to 1.72.10 (#2346) renovate[bot]
- e692f9b chore(deps): update dependency tunit to 1.69.21 (#2343) renovate[bot]
- 8d2e79b chore(deps): update github actions (#2353) renovate[bot]
๐ Full Changelog: v16.3.0...v16.4.0
๐ Contributions
๐ Thanks to all the contributors: @glennawatson
๐ค Automated services that contributed: renovate[bot]