Skip to content

Generated request helpers

Run the complete page example.

Behind a Refit interface call are several steps: filling in the URL, adding headers, writing the body, sending the request and reading the reply. The source generator writes that code for each interface method, and it calls GeneratedRequestRunner to carry out many of the steps.

You do not call these helpers for an ordinary service call. This page shows the code Refit generates for common interface methods, so you can read it and debug it. Each section then shows what a helper returns for a given input. If you call a helper yourself, you also choose the formatting, cancellation and ownership rules that the generator normally chooses from your interface.

The generated excerpts on this page are trimmed from the generator's output. They drop the global:: prefixes and the refit prefix on local names, and they show enum values by name where the generator writes a cast. settings is the client's RefitSettings, and Client is its HttpClient.

Build a path

You write methods with route placeholders:

public interface IProductsApi
{
    [Get("/products/{id}")]
    Task<Product> GetAsync(int id);

    [Get("/files/{**path}")]
    Task<Stream> GetFileAsync(string path);
}

Refit generates a BuildRequestPath call with the placeholder's position worked out at compile time. For the integer id, it uses the generic overload when default formatting applies:

useDefaultFormatting
    ? GeneratedRequestRunner.BuildRequestPath("/products/{id}", settings.AllowUnmatchedRouteParameters, (10, 14), id)
    : GeneratedRequestRunner.BuildRequestPath("/products/{id}", settings.AllowUnmatchedRouteParameters, [((10, 14), GeneratedRequestRunner.FormatUrlParameter(settings, id, GeneratedParameterAttributeProvider.Empty, typeof(int)))])

For the catch-all {**path}, it escapes the value with RoundTripEscapePath and marks it as already encoded:

GeneratedRequestRunner.BuildRequestPath(
    "/files/{**path}",
    settings.AllowUnmatchedRouteParameters,
    [((7, 15), GeneratedRequestRunner.RoundTripEscapePath(path?.ToString(), settings, GeneratedParameterAttributeProvider.Empty, typeof(string)), true)])

BuildRequestPath takes placeholder ranges with an inclusive start and an exclusive end. Keep the ranges in order, do not let them overlap, and include the braces in each range. The overload taking string values escapes each replacement. Its overload with a PreEncoded flag appends flagged values verbatim. A null replacement for an optional {name?} removes the / before it. A plain {name} with a null value leaves an empty segment. The two-argument overload checks a template that has no replacements. Any unresolved placeholder throws ArgumentException unless allowUnmatchedParameter is true.

string byName = GeneratedRequestRunner.BuildRequestPath("/products/{name}", false, [((10, 16), "shoes/boots")]); // "/products/shoes%2Fboots"
string order = GeneratedRequestRunner.BuildRequestPath("/orders/{id}", false, (8, 12), 42, "D6"); // "/orders/000042"
string file = GeneratedRequestRunner.RoundTripEscapePath("reports/2026 q3.pdf", settings, GeneratedParameterAttributeProvider.Empty, typeof(string)); // "reports/2026%20q3.pdf"

The generic overload without a format appends an invariant formatted span without escaping it, when it fits its buffer. The generator uses it only for unformatted integers, whose digits and optional minus sign are safe in a URL. Do not use that overload for other ISpanFormattable values. The generic overload with a format escapes the rendered value and supports other span-formattable values. The no-format generic overload is compiled under NET6_0_OR_GREATER, and its formatted counterpart under NET8_0_OR_GREATER. Both are present on Refit's .NET 8 and later targets and absent on its .NET Framework targets.

RoundTripEscapePath keeps the / separators of a catch-all route value, and formats and escapes each section between them. Its result is already escaped, so insert it with PreEncoded = true. Otherwise the percent signs are escaped a second time.

Resolve the request URL

Refit generates a BuildRelativeUri call around every path. A [QueryUriFormat] method adds a fourth argument with its UriFormat:

var request = new HttpRequestMessage(
    HttpMethod.Get,
    GeneratedRequestRunner.BuildRelativeUri(Client, "/products", settings.UrlResolution));

BuildRelativeUri returns a relative Uri, not the final absolute request address. With UrlResolutionMode.RefitLegacy, it requires a leading slash and prefixes the path of the client's base address, without that path's trailing slash. A missing base address throws InvalidOperationException. With Rfc3986, it leaves the relative path for HttpClient to resolve. The overload taking UriFormat re-encodes the full path and query in legacy mode. RFC mode ignores that argument.

HttpClient httpClient = new() { BaseAddress = new Uri("https://api.example.com/v2/") };
Uri legacy = GeneratedRequestRunner.BuildRelativeUri(httpClient, "/products", UrlResolutionMode.RefitLegacy); // "/v2/products"
Uri rfc = GeneratedRequestRunner.BuildRelativeUri(httpClient, "products", UrlResolutionMode.Rfc3986); // "products"

You write a [Url] parameter when the caller supplies the whole address:

[Get("")]
Task<Stream> DownloadAsync([Url] string url);

Refit generates a check, then uses the address as it is:

var absoluteUrl = GeneratedRequestRunner.RequireAbsoluteUrl(url);
var request = new HttpRequestMessage(HttpMethod.Get, new Uri(absoluteUrl, UriKind.Absolute));

RequireAbsoluteUrl accepts a string or a Uri, and returns its absolute URL text. A Uri contributes its OriginalString. It rejects null, empty and relative values with ArgumentException. For example, RequireAbsoluteUrl("https://cdn.example.com/images/42.png") returns the same text.

The check tests for UriKind.Absolute. It does not require an HTTP or HTTPS scheme. On Linux, RequireAbsoluteUrl("/items") returns "/items", which .NET accepts as a file URI. A generated [Url] request can then reach HTTP dispatch with an unsupported scheme, instead of failing this helper's argument check. The complete sample shows this limitation. Always pass an explicit HTTP or HTTPS URL.

Query building and formatting covers BuildQueryKey, FormatInvariant, FormatUrlParameter, the three default-formatter guards, and AddFormattedCollectionProperty.

Set headers and request options

You write header, property and timeout attributes:

public interface IProductsApi
{
    [Post("/orders")]
    Task CreateAsync([Body] Order order, [Header("X-Request-Id")] string requestId, CancellationToken cancellationToken);

    [Get("/products")]
    [Timeout(5000)]
    Task<List<Product>> ListAsync([HeaderCollection] IDictionary<string, string> headers, [Property("TraceId")] int traceId);
}

Refit generates one helper call for each. Every method also gets the AddConfiguredRequestOptions call. These lines come from both methods:

GeneratedRequestRunner.SetHeader(request, "X-Request-Id", requestId?.ToString(), settings.ValidateHeaders);
GeneratedRequestRunner.AddHeaderCollection(request, headers, settings.ValidateHeaders);
GeneratedRequestRunner.AddConfiguredRequestOptions(request, settings, typeof(IProductsApi));
GeneratedRequestRunner.AddRequestProperty<int>(request, "TraceId", traceId);
GeneratedRequestRunner.SetRequestTimeout(request, 5000);

SetHeader removes an earlier request or content header with the same name, then adds the new value. Null removes a header without adding one. On a method that accepts a body, it can create empty content so a content header has a place to live. It strips CR and LF from the name and value. With validateHeaders: true, a malformed value can throw FormatException. Otherwise it adds the value with the headers' TryAddWithoutValidation method. AddHeaderCollection applies the same rules to each dictionary entry. A null dictionary does nothing. Later values replace earlier values with the same key.

using HttpRequestMessage request = new(HttpMethod.Get, "/products");
GeneratedRequestRunner.SetHeader(request, "X-Api-Version", "1", validateHeaders: true);
GeneratedRequestRunner.SetHeader(request, "X-Api-Version", "2", validateHeaders: true);
// request.Headers.GetValues("X-Api-Version") returns only "2"

AddConfiguredRequestOptions applies the settings' request options and the interface type. On .NET 8 and later it also applies the configured HTTP version and version policy. AddRequestProperty<TValue> sets a typed HttpRequestMessage.Options value on those targets. On .NET Framework it uses the request's Properties dictionary. SetRequestTimeout stores the per-call milliseconds for the sending helpers. A positive value applies a timeout in addition to cancellation. Zero or a negative value turns this timeout off. Storing the option does not start a timer or send a request.

Create body content

You write a [Body] parameter. For the CreateAsync method above, Refit generates:

request.Content = GeneratedRequestRunner.CreateBodyContent<Order>(
    settings,
    order,
    BodySerializationMethod.Default,
    !settings.Buffered);
request.Content = GeneratedRequestRunner.CompressBodyContent(
    request.Content,
    settings,
    RequestCompression.Default,
    CompressionLevel.Optimal);

CreateBodyContent<TBody> returns an existing HttpContent unchanged and wraps a Stream with CreateStreamContent. With BodySerializationMethod.Default, a string is sent as raw text. Other values, or the Serialized mode, use the configured content serializer. For ordinary values, this method supports Default and Serialized (and the obsolete Json value, kept for compatibility). Other modes throw ArgumentOutOfRangeException. Generated code calls the separate URL-encoded or JSON Lines helpers for those modes. streamBody: true writes serialized content through a streaming wrapper, unless the settings choose synchronous serialization, which already creates a buffer.

using HttpContent note = GeneratedRequestRunner.CreateBodyContent(settings, "Leave at the front desk", BodySerializationMethod.Default, streamBody: false);
// await note.ReadAsStringAsync() returns "Leave at the front desk", sent as text/plain

CreateJsonLinesBodyContent<TBody> serializes each element of an enumerable as a JSON value, with a newline between values and no trailing newline. It treats a string as a single value, not as a sequence of characters. Existing content and streams pass through, as with the other body helpers. For example, CreateJsonLinesBodyContent(settings, new[] { 3, 7 }) writes 3, a newline, then 7.

For a body declared as IEnumerable<T>, generated code calls CreateTypedJsonLinesBodyContent<T> instead. It writes the same bytes. For a body declared as IAsyncEnumerable<T>, generated code calls CreateAsyncJsonLinesBodyContent<T>, which writes each element as the producer yields it. Upload many records shows both from the caller's side.

You write a [Multipart] method:

[Multipart]
[Post("/upload")]
Task UploadAsync([AliasAs("file")] Stream file, Product metadata);

Refit generates one part per argument:

var multipart = new MultipartFormDataContent("----MyGreatBoundary");
if (file != null)
{
    multipart.Add(GeneratedRequestRunner.CreateStreamContent(file), "file", "file");
}
if (metadata != null)
{
    multipart.Add(GeneratedRequestRunner.SerializeMultipartPart(settings, metadata, "metadata"), "metadata");
}
request.Content = multipart;

SerializeMultipartPart<T> serializes one part through the configured serializer. It does not create a multipart container. It wraps a serializer failure in ArgumentException, with the field name and the original exception.

CreateStreamContent leaves the caller's stream open when the content is disposed. You still own that stream and must dispose it. Existing content that a helper returns unchanged does not get this stream protection.

CompressBodyContent resolves RequestCompression.Default from the settings. Explicit None returns the same content. An explicit coding also uses the compression level you pass, while Default uses the settings' level. Compressor options in the settings can override level-based construction. The returned compression content owns its inner content, so dispose the returned wrapper.

using HttpContent gzip = GeneratedRequestRunner.CompressBodyContent(new StringContent("""{"orderId":42}"""), settings, RequestCompression.GZip, CompressionLevel.Fastest);
// gzip.Headers.ContentEncoding contains "gzip"

Add using System.IO.Compression; for CompressionLevel. GZip is available on all Refit targets, Brotli on .NET 8 and later, and Zstandard on .NET 11 and later. Requesting an unavailable coding throws PlatformNotSupportedException. The .NET 10 sample checks this exception for Zstandard. It does not verify successful .NET 11 Zstandard compression or its options.

Supply form descriptors

You write a URL-encoded body. When every property is a simple value, Refit generates code that reads each property directly and builds a FormUrlEncodedContent. That code calls CanUnrollForm, BuildQueryKey and FormatInvariant, and it falls back to CreateUrlEncodedBodyContent(settings, form) when the serializer is not SystemTextJsonContentSerializer. When a property is a collection, Refit generates an array of FormField<TBody> descriptors instead:

public sealed class TagForm
{
    public string? Name { get; set; }

    [Query(CollectionFormat.Csv)]
    public string[]? Tags { get; set; }
}

[Post("/tags")]
Task SaveTagsAsync([Body(BodySerializationMethod.UrlEncoded)] TagForm form);
private static readonly FormField<TagForm>[] formFields = new FormField<TagForm>[]
{
    new FormField<TagForm>(static body => (object?)body.Name, "Name", null, null, null, null, false),
    new FormField<TagForm>(static body => (object?)body.Tags, "Tags", null, null, null, CollectionFormat.Csv, false),
};

request.Content = GeneratedRequestRunner.CreateUrlEncodedBodyContent<TagForm>(settings, form, formFields);

CreateUrlEncodedBodyContent<TBody>(settings, body) flattens form values from the declared body's public properties or dictionary entries. It escapes a string as one whole value, so a=b becomes a%3Db. It does not parse the string as an already encoded form. Existing content and streams pass through. This overload uses reflection to flatten an ordinary object.

The overload taking FormField<TBody>[] can use the descriptors' getters instead. That path applies only to a non-null object that is not a dictionary, with a SystemTextJsonContentSerializer configured. Other serializer types can need their property-name hook and fall back to reflection. Nested complex form values can also require runtime property discovery. The descriptors avoid discovery for known simple fields. They do not guarantee it for every body shape.

FormField<TBody> stores the Getter, ClrName, ExplicitName, PrefixSegment, Format, CollectionFormat and SerializeNull passed to its constructor, as read-only properties. ResolveFieldName uses ExplicitName when it is set. Otherwise it formats ClrName with the key formatter you pass. It then prepends the prefix verbatim. An explicit collection format overrides the settings' default. SerializeNull: true emits an empty field for a null value; false omits it.

TagForm form = new() { Name = "Summer sale", Tags = ["shoes", "hats"] };
FormField<TagForm>[] fields =
[
    new(static value => value.Name, nameof(TagForm.Name), "name", null, null, null, false),
    new(static value => value.Tags, nameof(TagForm.Tags), null, null, null, CollectionFormat.Csv, false),
];
using HttpContent content = GeneratedRequestRunner.CreateUrlEncodedBodyContent(settings, form, fields);
string body = await content.ReadAsStringAsync(); // "name=Summer+sale&Tags=shoes%2Chats"

CanUnrollForm reports whether the body is a plain non-null object. It returns false for strings, streams, existing content and dictionaries. It does not check the serializer or send a request.

Send a built request

Refit generates one dispatch call at the end of each method. The call depends on the return type:

You writeRefit generates
Task CreateAsync(..., CancellationToken cancellationToken)SendVoidAsync(Client, request, settings, settings.Buffered, cancellationToken)
Task<List<Product>> ListAsync(...)SendAsync<List<Product>, List<Product>>(Client, request, settings, false, true, false, CancellationToken.None)
Task<ApiResponse<Order>> SubmitAsync([Body(BodySerializationMethod.UrlEncoded)] OrderForm form)SendAsync<ApiResponse<Order>, Order>(Client, request, settings, true, true, settings.Buffered, CancellationToken.None)
IObservable<List<Product>> WatchAsync()SendObservable<List<Product>, List<Product>>(Client, BuildRequest, settings, false, true, false, CancellationToken.None)
IAsyncEnumerable<Product> StreamAsync(CancellationToken cancellationToken)StreamAsync<Product>(Client, request, settings, cancellationToken)

The generated code passes the method's CancellationToken when it has one, and CancellationToken.None when it does not. It passes settings.Buffered as bufferBody when the method sends a serialized or form body.

All four dispatch methods require the client's BaseAddress, even when a request has an absolute URI. They apply the configured authorization getter, exception handling and positive per-call timeout. The task methods dispose the request after sending it. Choose the flags to match the return type, as the generator does.

SendVoidAsync sends a request with no returned body and disposes the response. The default exception factory throws on an HTTP error. SendAsync<T, TBody> can deserialize T, return the raw response, content or stream, or build an API response wrapper. isApiResponse: true requires a supported wrapper type for T, and TBody is its body type. bufferBody controls buffering of the request content before sending, not the response content.

shouldDisposeResponse decides who disposes the response. Generated code passes true for every result except HttpResponseMessage, HttpContent and Stream, including an ApiResponse<T> whose body it has already read. For those three results it passes false, because the caller reads from the live response and must dispose it. For a plain result with an HTTP error, the pipeline hands the response to the thrown exception instead.

List<Product>? products = await GeneratedRequestRunner.SendAsync<List<Product>, List<Product>>(
    httpClient,
    new HttpRequestMessage(HttpMethod.Get, "/products"),
    settings,
    isApiResponse: false,
    shouldDisposeResponse: true,
    bufferBody: false,
    cancellationToken);

SendObservable<T, TBody> returns a cold observable: each subscription starts a new request. For an IObservable<T> method, generated code passes a local function that builds a fresh request, because each request is disposed after use. The method token and subscription token are linked when both can cancel. The same result and ownership flags apply as for SendAsync.

StreamAsync<T> sends when you start enumerating and requires an IStreamingContentSerializer. The built-in System.Text.Json serializer supports it. The response media type selects JSON array, JSON Lines or server-sent event framing. The sequence disposes the request, response and body stream when enumeration finishes or is disposed. It links the method token and consumer token when both can cancel. A positive request timeout also applies while reading. Unlike the observable, this call captures one request. Do not enumerate the sequence a second time, because its request is already disposed.

The complete sample also checks the streamed values and their order, cold observable dispatch, raw response, content and stream results, request options, and decompressed GZip and Brotli payloads. Method metadata describes the reflected information objects.

Path and formatting overloads

All methods below are static members of GeneratedRequestRunner. Arguments are required unless the signature shows a default. settings is the client's RefitSettings. A range is a value tuple of two int positions: inclusive start and exclusive end.

OverloadDescriptionParametersReturns
BuildRequestPath(string relativePathTemplate, bool allowUnmatchedParameter)Validates a parameterless route template before using it as a request path.string relativePathTemplate: route; bool allowUnmatchedParameter: whether unresolved placeholders are allowed.string: unchanged template, or throws for unresolved placeholders when the flag is false.
BuildRequestPath(string relativePathTemplate, bool allowUnmatchedParameter, ReadOnlySpan<((int StartIdx, int EndIdx) Range, string? Value)> uriParams)Replaces several path placeholders using default escaping.string template and bool unmatched flag; ReadOnlySpan uriParams: ordered placeholder ranges and replacement strings.string: path with escaped replacements and optional null segments removed.
BuildRequestPath(string relativePathTemplate, bool allowUnmatchedParameter, ReadOnlySpan<((int StartIdx, int EndIdx) Range, string? Value, bool PreEncoded)> uriParams)Replaces several placeholders while allowing selected values to bypass escaping.string template and bool unmatched flag; ReadOnlySpan uriParams: ordered ranges, values, and per-value encoding flags.string: path with replacements escaped unless their PreEncoded flag is true.
BuildRequestPath<T>(string relativePathTemplate, bool allowUnmatchedParameter, (int StartIdx, int EndIdx) range, T value)Replaces one placeholder with an invariant unformatted numeric value.string template; bool unmatched flag; tuple range: one placeholder; value: an ISpanFormattable. Requires T : ISpanFormattable.string: path with an invariant formatted value. Use this overload only for unformatted integers, as explained above.
BuildRequestPath<T>(string relativePathTemplate, bool allowUnmatchedParameter, (int StartIdx, int EndIdx) range, T value, string? format)Replaces one placeholder with an invariant value using a format string.string template; bool unmatched flag; tuple range: placeholder; ISpanFormattable value; string format: format or null. Requires T : ISpanFormattable.string: path with an escaped invariant formatted replacement.
BuildRelativeUri(HttpClient client, string relativePath, UrlResolutionMode urlResolution)Combines a route with the client base path under the selected resolution rule.HttpClient client: supplies the base path; string relativePath: route; UrlResolutionMode urlResolution: resolution rule.Uri: relative URI for HttpClient to resolve.
BuildRelativeUri(HttpClient client, string relativePath, UrlResolutionMode urlResolution, UriFormat queryUriFormat)Builds a relative URI and applies the legacy query rendering mode when relevant.HttpClient client; string relativePath; UrlResolutionMode urlResolution; UriFormat queryUriFormat: legacy path/query escaping rule.Uri: relative URI. RFC resolution ignores queryUriFormat.
RequireAbsoluteUrl(object? url)Rejects a URL value that is absent or not absolute.object url: a string or Uri with an absolute address.string: original URL text. Throws ArgumentException if it cannot be parsed as absolute. This does not enforce HTTP/HTTPS.
RoundTripEscapePath(string? value, RefitSettings settings, ICustomAttributeProvider attributeProvider, Type type)Formats and escapes a catch-all path without escaping its separators.string value: catch-all path or null; RefitSettings settings; ICustomAttributeProvider attributeProvider: formatting attributes; Type type: declared value type.string: formatted and escaped path sections with / separators retained.
FormatUrlParameter(RefitSettings settings, object? value, ICustomAttributeProvider attributeProvider, Type type)Formats one value through the registered or default URL formatter.RefitSettings settings; object value: value or null; ICustomAttributeProvider attributeProvider: attributes; Type type: declared type.string, nullable: result from the selected URL formatter.
FormatInvariant<T>(T value, string? format)Renders an IFormattable using invariant culture without URL escaping.value: an IFormattable; string format: format or null. Requires T : IFormattable.string: invariant formatted value without URL escaping.
BuildQueryKey(RefitSettings settings, string clrName, string? explicitName, string? prefixSegment)Builds the final query key from an alias or formatted CLR name and optional prefix.RefitSettings settings; string clrName: declared name; string explicitName: alias or null; string prefixSegment: prefix including delimiter, or null.string: explicit or formatted name with the prefix prepended.
UsesDefaultUrlParameterFormatting(RefitSettings settings)Checks whether URL values can use the built-in formatter fast path.RefitSettings settings: formatters to inspect.bool: whether inline URL formatting matches the pristine default formatter and the formatter map is empty.
UsesDefaultFormUrlEncodedParameterFormatting(RefitSettings settings)Checks whether form values use the exact built-in formatter type.RefitSettings settings: formatter to inspect.bool: whether the form formatter has the exact built-in default type.
UsesDefaultUrlParameterKeyFormatting(RefitSettings settings)Checks whether query keys use the exact built-in key formatter type.RefitSettings settings: formatter to inspect.bool: whether the key formatter has the exact built-in default type.
AddFormattedCollectionProperty(ref GeneratedQueryStringBuilder builder, RefitSettings settings, IEnumerable? values, string key, CollectionFormat collectionFormat, bool preEncoded, (Type ElementProviderType, ICustomAttributeProvider JoinedProvider, Type JoinedType) formatting)Formats and appends a collection-valued query property using the configured collection rule.GeneratedQueryStringBuilder builder: updated by reference; RefitSettings settings; IEnumerable values: collection or null; string key; CollectionFormat collectionFormat; bool preEncoded; tuple formatting: element Type, joined-value ICustomAttributeProvider, and joined Type.void; appends values using the two formatting passes described in query building. Null appends nothing.

Header and option overloads

OverloadDescriptionParametersReturns
SetHeader(HttpRequestMessage request, string name, string? value, bool validateHeaders)Replaces one request header and optionally validates its syntax.HttpRequestMessage request; string name: header name; string value: replacement or null; bool validateHeaders: whether to validate header syntax.void; replaces the header, or removes it for null.
AddHeaderCollection(HttpRequestMessage request, IDictionary<string, string>? headers, bool validateHeaders)Applies a collection of header replacements to the request.HttpRequestMessage request; IDictionary<string, string> headers: replacements or null; bool validateHeaders: whether to validate syntax.void; applies SetHeader to each entry. Null does nothing.
AddConfiguredRequestOptions(HttpRequestMessage request, RefitSettings settings, Type interfaceType)Copies configured request options and HTTP version settings onto a request.HttpRequestMessage request; RefitSettings settings: options and version rules; Type interfaceType: Refit interface.void; stores request options and interface type, plus HTTP version settings on modern .NET.
AddRequestProperty<TValue>(HttpRequestMessage request, string key, TValue value)Stores one typed request option for later request execution.HttpRequestMessage request; string key: option key; value: option value.void; sets a typed option, or a dictionary entry on .NET Framework.
SetRequestJsonTypeInfo<T>(HttpRequestMessage request, JsonTypeInfo<T>? typeInfo)Stores the metadata that describes the response body, so the reply is read with it. Generated code calls it for a method that has a JsonTypeInfo<T> parameter.HttpRequestMessage request; JsonTypeInfo<T> typeInfo: metadata for the reply body, or null to store nothing. .NET 8 and later.void; stores the metadata as a request option.
SetRequestTimeout(HttpRequestMessage request, int timeoutMilliseconds)Records the per-request timeout for the send helper to apply.HttpRequestMessage request; int timeoutMilliseconds: timeout in milliseconds.void; stores a timeout for dispatch to apply.

Body helper overloads

TBody is the declared body type. The URL-encoded overloads require its public properties to survive trimming when they use reflection. Read AOT guidance before using them in a native app.

OverloadDescriptionParametersReturns
CreateBodyContent<TBody>(RefitSettings settings, TBody body, BodySerializationMethod serializationMethod, bool streamBody)Serializes a request body according to the selected body mode, preserving supplied content and streams.RefitSettings settings; body: value to send; BodySerializationMethod serializationMethod; bool streamBody: whether serialized content streams.HttpContent: existing content, protected stream content, raw text, or serialized body as described above.
CreateBodyContent<TBody>(RefitSettings settings, TBody body, JsonTypeInfo<TBody>? typeInfo, BodySerializationMethod serializationMethod, bool streamBody)Serializes a request body with the metadata a method parameter supplies. It follows the same body rules as the overload above.RefitSettings settings; body: value to send; JsonTypeInfo<TBody> typeInfo: metadata for TBody, or null to use the serializer's own lookup; BodySerializationMethod serializationMethod; bool streamBody.HttpContent: as above, with the body written through IJsonTypeInfoContentSerializer when typeInfo is set. Throws InvalidOperationException when the serializer does not implement it. .NET 8 and later.
CreateJsonLinesBodyContent<TBody>(RefitSettings settings, TBody body)Creates newline-delimited JSON content from one value or an enumerable body.RefitSettings settings; body: one value or a sequence of values.HttpContent: JSON Lines content, or existing content/stream handling.
CreateTypedJsonLinesBodyContent<TElement>(RefitSettings settings, IEnumerable<TElement>? body)Generator-facing. Creates JSON Lines content for a body declared as IEnumerable<TElement>.RefitSettings settings; body: the sequence, or null.HttpContent: writes each element as TElement when that gives the same JSON as CreateJsonLinesBodyContent, which is when TElement has no derived types and the serializer is the built-in System.Text.Json one. Otherwise it returns exactly what CreateJsonLinesBodyContent returns.
CreateAsyncJsonLinesBodyContent<TElement>(RefitSettings settings, IAsyncEnumerable<TElement>? body)Generator-facing. Creates JSON Lines content for a body declared as IAsyncEnumerable<TElement>.RefitSettings settings; body: the asynchronous sequence, or null.HttpContent: single-use content that writes each element as TElement as the producer yields it, ending every line with a line feed. A null body is written as one null line.
CreateStreamContent(Stream stream)Wraps a caller-owned stream without taking ownership of that stream.Stream stream: caller-owned body stream.HttpContent: wrapper that leaves the stream open when disposed.
CreateUrlEncodedBodyContent<TBody>(RefitSettings settings, TBody body)Converts a body to URL-encoded form content, with special handling for existing content, streams and strings.RefitSettings settings; body: form object, dictionary, string, content or stream.HttpContent: URL-encoded form or existing content/stream handling. Object flattening uses reflection.
CreateUrlEncodedBodyContent<TBody>(RefitSettings settings, TBody body, FormField<TBody>[] fields)Converts a body to URL-encoded form content using generated field descriptors when supported.RefitSettings settings; body: form value; fields: form descriptors with direct getters.HttpContent: form content using eligible descriptors, otherwise the reflection path described above.
CanUnrollForm(object? body)Checks whether a body can use the generated property-by-property form path.object body: candidate form value, or null.bool: true for non-null values other than strings, streams, HTTP content and dictionaries.
SerializeMultipartPart<T>(RefitSettings settings, T value, string fieldName)Serializes one multipart value with the configured content serializer.RefitSettings settings; value: one part; string fieldName: name used in an error.HttpContent: serialized part. Serializer failures become ArgumentException.
CompressBodyContent(HttpContent content, RefitSettings settings, RequestCompression compression, CompressionLevel level)Applies the resolved request compression setting to HTTP content.HttpContent content: input; RefitSettings settings: defaults/options; RequestCompression compression: coding; CompressionLevel level: effort for explicit coding.HttpContent: owning compression wrapper, or the same content when no coding applies.

Dispatch overloads

T is the caller's result type. TBody is the body type inside an API response wrapper. For each dispatch, supply an HttpClient with BaseAddress set and the client's RefitSettings. The shared flags have these meanings:

ParameterTypeValue
isApiResponsebooltrue when T is a supported response wrapper.
shouldDisposeResponsebooltrue for a fully consumed result, including an ApiResponse<T>. Use false when returning HttpResponseMessage, HttpContent or Stream.
bufferBodyboolWhether to buffer request content before sending.
OverloadDescriptionParametersReturns
SendVoidAsync(HttpClient client, HttpRequestMessage request, RefitSettings settings, bool bufferBody, CancellationToken cancellationToken)Sends a request whose successful result has no response body.HttpClient client; HttpRequestMessage request: message to send; RefitSettings settings; bool bufferBody: flag above; CancellationToken cancellationToken: request cancellation.Task: completion without a result. Disposes the request and response.
SendAsync<T, TBody>(HttpClient client, HttpRequestMessage request, RefitSettings settings, bool isApiResponse, bool shouldDisposeResponse, bool bufferBody, CancellationToken cancellationToken)Sends a request and processes its response as a deserialized value or API response wrapper.HttpClient client; HttpRequestMessage request; RefitSettings settings; three bool flags above; CancellationToken cancellationToken: request cancellation.Task<T?>: deserialized, raw, or wrapped result. Disposes the request. Response ownership follows the flag.
SendObservable<T, TBody>(HttpClient client, Func<HttpRequestMessage> requestFactory, RefitSettings settings, bool isApiResponse, bool shouldDisposeResponse, bool bufferBody, CancellationToken methodCancellationToken)Creates a cold observable that builds and sends a fresh request for each subscription.HttpClient client; Func<HttpRequestMessage> requestFactory: creates a fresh message per subscription; RefitSettings settings; three bool flags above; CancellationToken methodCancellationToken: caller cancellation.IObservable<T?>: sends one request per subscription and delivers its result or error. See observable replies.
StreamAsync<T>(HttpClient client, HttpRequestMessage request, RefitSettings settings, CancellationToken methodCancellationToken, CancellationToken cancellationToken = default)Sends a request and exposes the response body as an asynchronous stream.HttpClient client; HttpRequestMessage request: one message; RefitSettings settings; CancellationToken methodCancellationToken: caller token; CancellationToken cancellationToken: enumeration token, default non-cancelable.IAsyncEnumerable<T?>: one streaming response. Enumeration/disposal releases its request, response and stream.

Form field reference

FormField<TBody> stores a getter and formatting rules for one field. Its properties are read-only and retain the constructor arguments. None of the arguments has a default.

OverloadDescriptionParametersReturns
FormField(Func<TBody, object?> getter, string clrName, string? explicitName, string? prefixSegment, string? format, CollectionFormat? collectionFormat, bool serializeNull)Creates a descriptor that reads and formats one URL-encoded form field.Func<TBody, object?> getter: reads a field; string clrName: declared name; nullable string arguments: explicit name, prefix with delimiter and value format; nullable CollectionFormat collectionFormat: override or settings default; bool serializeNull: whether null emits an empty field.A FormField<TBody> descriptor.
ResolveFieldName(IUrlParameterKeyFormatter urlParameterKeyFormatter)Resolves the final form key from the explicit name or configured key formatter.IUrlParameterKeyFormatter urlParameterKeyFormatter: formats ClrName when no explicit name is set.string, nullable: resolved name with the prefix prepended.
PropertyTypeValue
GetterFunc<TBody, object?>Reads the field value from a body instance.
ClrNamestringDeclared property name.
ExplicitNamestring, nullableAlias or serializer name; null uses the key formatter.
PrefixSegmentstring, nullablePrefix including delimiter; null adds none.
Formatstring, nullableValue format; null uses default formatting.
CollectionFormatCollectionFormat, nullableExplicit collection rule; null uses settings.
SerializeNullbooltrue emits an empty field for null; false omits it.
UrlResolutionMode valueNumeric valueMeaning
RefitLegacy0Prefix the base-address path and require a leading slash.
Rfc39861Use standard URI resolution. See URL settings.

Source: path/header helpers, body helpers, dispatch entry points, shared execution, streaming execution, form descriptors, and form flattening.