5.39Frozen Parameter Types

Updated on Aug 20, 2026~8 min read

In the previous chapters, we mentioned frozen parameter types several times, and now we can finally discuss them in depth.

In the system, Action<HttpRequestMessage>, Action<HttpRequestBuilder>, Action<HttpMultipartFormDataBuilder>, HttpCompletionOption, and CancellationToken are defined as frozen parameter types. They specifically serve HTTP declarative request interfaces to provide additional configuration and operation capabilities. These frozen parameter types can greatly extend the functionality of HTTP declarative request interfaces, enabling them to cover a wider range of use cases.

  • Action<HttpRequestMessage>

This parameter allows developers to apply additional configuration to the HttpRequestMessage sent by HttpClient when calling an HTTP declarative interface. For example, adding custom HTTP headers, setting authentication information, and so on. The corresponding HTTP declarative extractor is implemented as the HttpRequestMessageDeclarativeExtractor type, which is responsible for parsing a single Action<HttpRequestMessage> parameter and providing operations before the request is sent.

cs
public interface IHttpService : IHttpDeclarative{    [Post("https://furion.net/")]    Task<string> PostStringAsync([QueryParam] int id, [Body("application/json")] object body, Action<HttpRequestMessage>? configure = null)}
cs
// Default callawait httpService.PostStringAsync(1, new { id = 1, name = "Furion" });// Provide more HttpRequestMessage configurationawait httpService.PostStringAsync(1, new { id = 1, name = "Furion" }, requestMessage =>{    requestMessage.Headers.TryAddWithoutValidation("header1", "value1");    // For example, add a request header named "header1"});
  • Action<HttpRequestBuilder>

This parameter allows developers to apply additional configuration to the HttpRequestBuilder when calling an HTTP declarative interface. For example, adding custom HTTP headers, setting authentication information, and so on. The corresponding HTTP declarative extractor is implemented as the HttpRequestBuilderDeclarativeExtractor type, which is responsible for parsing a single Action<HttpRequestBuilder> parameter and providing additional configuration for building the HttpRequestBuilder instance.

cs
public interface IHttpService : IHttpDeclarative{    [Post("https://furion.net/")]    Task<string> PostStringAsync([QueryParam] int id, [Body("application/json")] object body, Action<HttpRequestBuilder>? configure = null)}
cs
// Default callawait httpService.PostStringAsync(1, new { id = 1, name = "Furion" });// Provide more HttpRequestBuilder configurationawait httpService.PostStringAsync(1, new { id = 1, name = "Furion" }, builder =>{    builder.AddBearerAuthentication("your-token");   // For example, add Bearer authorization});
  • Action<HttpMultipartFormDataBuilder>

This parameter is used to configure the settings of multipart form data. Through it, developers can add files, set file types, and so on. The corresponding HTTP declarative extractor is implemented as the HttpMultipartFormDataBuilderDeclarativeExtractor type, which is responsible for parsing a single Action<HttpMultipartFormDataBuilder> parameter and providing additional configuration for building the HttpMultipartFormDataBuilder multipart form instance.

cs
public interface IHttpService : IHttpDeclarative{    [Post("https://furion.net/")]    Task<string> PostStringAsync([Multipart] string name, Action<HttpMultipartFormDataBuilder>? configure = null);}
cs
// Default callawait httpService.PostStringAsync("Furion");// Provide more multipart form content configurationawait httpService.PostStringAsync("Furion", multipart =>{    multipart.AddFileAsStream(@"C:\Workspaces\httptest.jpg", "files", contentType: "image/jpeg");    multipart.AddFileFromBase64String("77u/5rWL6K+V5paH5Lu25YaF5a65", "files");    multipart.AddFileFromRemote("https://furion.net/img/furionlogo.png", "files");});
  • HttpCompletionOption

This parameter is used to specify how the HTTP response is read. For example, whether to wait until the entire response content has been read before returning, or to return after reading only the response headers.

cs
public interface IHttpService : IHttpDeclarative{    [Get("https://furion.net/")]    Task<Stream> GetStreamAsync([QueryParam] string version, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead);}
cs
// Default callawait httpService.GetStreamAsync("v4");// Customize the response reading methodawait httpService.GetStreamAsync("v5", HttpCompletionOption.ResponseHeadersRead);
  • CancellationToken

This parameter allows developers to provide cancellation configuration when sending an HTTP request. Through it, the request can be set to be canceled under specific conditions.

cs
public interface IHttpService : IHttpDeclarative{    [Get("https://furion.net/")]    Task<Stream> GetStreamAsync(CancellationToken cancellationToken = default);}
cs
// Default call (cannot be canceled)await httpService.GetStreamAsync("v4");// Set the request to be canceled after 100 millisecondsusing var cancellationTokenSource = new CancellationTokenSource();cancellationTokenSource.CancelAfter(100);await httpService.GetStreamAsync("v5", cancellationTokenSource.Token);  // Assume this request takes longer than 100 milliseconds

It is worth noting that these frozen parameter types can be combined, and are usually (recommended to be) placed at the end of the method parameter list as optional configuration. However, within the same method parameter definition, frozen parameters of the same type must be unique, otherwise an InvalidOperationException is thrown.

cs
public interface IHttpService : IHttpDeclarative{    // Combined usage is supported    [Post("https://furion.net/")]    Task<string> PostStringAsync([QueryParam] int id, [Body("application/json")] object body,        Action<HttpMultipartFormDataBuilder>? multipartConfigure = null,        Action<HttpRequestBuilder>? configure = null,        HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,        CancellationToken cancellationToken = default);    // Action<HttpRequestBuilder> type parameters are not unique, an exception will be thrown ❎    [Post("https://furion.net/")]    Task<string> PostStringAsync([QueryParam] int id, [Body("application/json")] object body,        Action<HttpRequestBuilder>? configure = null,        Action<HttpRequestBuilder>? configure1 = null);}

Through these frozen parameter types, HTTP declarative request interfaces not only greatly reduce the burden on developers writing HTTP request code, but also make the code structure clearer and easier to maintain and reuse.