Skip to content

Client Configuration

Every service generates a concrete {Service}Client and an I{Service}Client interface. You can construct the client directly or register it with the .NET service container.

For the common case, pass the endpoint directly:

var client = new WeatherClient(new Uri("https://api.example.com"));

Add a {Service}ClientConfig when you need NSmithy-level options such as protocol selection, auth, retry, interceptors, or idempotency tokens:

using NSmithy.Protocols.Grpc;
var client = new WeatherClient(
new Uri("https://api.example.com"),
new()
{
Protocol = new GrpcProtocol(),
IdempotencyTokenProvider = () => Guid.NewGuid().ToString(),
});

The endpoint argument wins over config.Endpoint when both are supplied.

{Service}ClientConfig is a per-service subclass of SmithyClientConfig. The endpoint constructor fills Endpoint for you; pass config as the second argument when you want to set client options.

OptionPurpose
EndpointThe service endpoint. Set by the endpoint constructor, and optional for the HttpClient constructor.
ProtocolThe wire protocol. Defaults to the service’s primary declared protocol.
EndpointResolverPer-operation endpoint resolution. Overrides the static Endpoint for request routing; can vary the endpoint by operation, add endpoint headers, and narrow auth schemes.
AuthSchemesConfigured auth schemes; the resolver installs the first scheme the service models. An empty list means anonymous.
RetryStrategyRuntime-owned retry policy. null disables runtime retries.
OperationTimeoutDeadline for one operation execution, spanning all retry attempts and backoff delays. Throws TimeoutException when exceeded; null (default) means no deadline.
InterceptorsProtocol-agnostic hooks for observing and modifying client execution.
IdempotencyTokenProviderOverrides the idempotency-token generator (default: a random GUID).

Everything except Endpoint is optional. The config is a per-service type (WeatherClientConfig), so service-specific options can be added later without changing the constructor signature.

The public constructors differ mainly by who owns the HTTP transport:

new WeatherClient(endpoint, config); // normal direct construction; endpoint wins over config.Endpoint
new WeatherClient(httpClient, config); // you own the HttpClient; endpoint from config.Endpoint ?? BaseAddress
new WeatherClient(runtime, config); // you own the lower-level runtime path

config is optional on all public constructors.

Keep the constructor choice simple:

  • Use the endpoint constructor for normal application code.
  • Use the generated Add{Service}Client helper for dependency injection.
  • Use the HttpClient constructor only when something else already owns and configures the HttpClient.
  • Use the runtime constructor only for custom transports and low-level tests.

The client implements IDisposable. When the client creates the HttpClient itself, Dispose releases it. When you supply an HttpClient or runtime, Dispose is a no-op, so the transport you own is never closed:

using var client = new WeatherClient(new Uri("https://api.example.com"));

For a long-lived application, prefer registering the client once with IHttpClientFactory over constructing one per call.

  • Authentication covers HTTP auth schemes and early-preview AWS SigV4 signing.
  • Retry covers runtime-owned retry configuration.
  • Interceptors covers client execution hooks.
  • Observability covers OpenTelemetry tracing and metrics.
  • Pagination covers the generated IAsyncEnumerable paginators for @paginated operations.
  • Transport covers endpoint, HttpClient, and low-level runtime ownership.
  • Dependency Injection covers Add{Service}Client, IHttpClientFactory, and typed-client lifetime.