Skip to content

Dependency Injection

NSmithy can generate an Add{Service}Client extension that registers the client as a typed IHttpClientFactory client. This is the recommended way to use a client with the .NET service container.

Enable the helper in the client project:

<PropertyGroup>
<SmithyGenerateDependencyInjection>true</SmithyGenerateDependencyInjection>
</PropertyGroup>

This flows into the generated smithy-build.json so the extension is only generated when enabled (it isn’t emitted otherwise). If your project uses an explicit smithy-build.json instead of one synthesized from a contracts reference, set it on the plugin directly:

{ "plugins": { "csharp-codegen": { "service": "...", "generateDependencyInjection": true } } }

It’s opt-in because the generated code depends on Microsoft.Extensions.Http. Reference that package (or the Microsoft.AspNetCore.App shared framework, which already provides it) when you enable it.

services.AddWeatherClient(new Uri("https://api.example.com"));

Then inject the interface anywhere:

public sealed class ForecastService(IWeatherClient weather)
{
public Task<GetForecastOutput> GetAsync(string city) =>
weather.GetForecastAsync(new GetForecastInput(city));
}

Add{Service}Client returns the IHttpClientBuilder, so you can chain handlers (logging, resilience, auth handlers) and other typed-client configuration:

services.AddWeatherClient(new Uri("https://api.example.com"))
.AddHttpMessageHandler<AuthHandler>();

If your application owns HttpClient setup, use the callback overload. This is where you set BaseAddress, timeouts, default headers, HTTP version policy, and other System.Net.Http.HttpClient settings:

services.AddWeatherClient(client =>
{
client.BaseAddress = new Uri("https://api.example.com");
client.Timeout = TimeSpan.FromSeconds(10);
});

NSmithy client options are configured separately from HttpClient options. The config callback uses the same {Service}ClientConfig that constructors take (see Client Configuration):

services.AddWeatherClient(
new Uri("https://api.example.com"),
config => config.Protocol = new GrpcProtocol());

You can combine both callbacks when you need both layers:

services.AddWeatherClient(
client =>
{
client.BaseAddress = new Uri("https://api.example.com");
client.Timeout = TimeSpan.FromSeconds(10);
},
config =>
{
config.Protocol = new GrpcProtocol();
config.AuthSchemes.Add(authScheme);
});

The helper configures the HttpClient for HTTP/2 automatically when the chosen protocol requires it (native gRPC).

The generated helper is preferred. It configures the typed client and applies protocol-specific HttpClient settings such as HTTP/2 for gRPC.

Generated clients are still plain typed clients, so manual registration works:

services.AddHttpClient<IWeatherClient, WeatherClient>(client =>
client.BaseAddress = new Uri("https://api.example.com"));

Use this only when you need full control over IHttpClientFactory registration. For non-default protocols or gRPC, prefer AddWeatherClient(...); otherwise you must configure the HttpClient version and policy yourself.

Outside of DI, the generated {Service}Client is constructed from a direct endpoint argument plus an optional {Service}ClientConfig, or from an HttpClient / runtime plus an optional config. See Client Configuration.