Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions docs/core/extensions/httpclient-factory-troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Even if `IHttpClientFactory` is used, it's still possible to hit the stale DNS p

`HttpClient` instances created by `IHttpClientFactory` are intended to be **short-lived**.

- Recycling and recreating `HttpMessageHandler`'s when their lifetime expires is essential for `IHttpClientFactory` to ensure the handlers react to DNS changes. `HttpClient` is tied to a specific handler instance upon its creation, so new `HttpClient` instances should be requested in a timely manner to ensure the client will get the updated handler.
- Recycling and recreating `HttpMessageHandler`s when their lifetime expires is essential for `IHttpClientFactory` to ensure the handlers react to DNS changes. `HttpClient` is tied to a specific handler instance upon its creation, so new `HttpClient` instances should be requested in a timely manner to ensure the client will get the updated handler.

- Disposing of such `HttpClient` instances **created by the factory** will not lead to socket exhaustion, as its disposal **does not** trigger disposal of the `HttpMessageHandler`. `IHttpClientFactory` tracks and disposes of resources used to create `HttpClient` instances, specifically the `HttpMessageHandler` instances, as soon their lifetime expires and there's no `HttpClient` using them anymore.

Expand Down Expand Up @@ -110,9 +110,9 @@ Consider the following examples of how the link between _typed_ and _named_ clie

❌ DO NOT register the _typed client_ separately — it is already registered automatically by the `AddHttpClient<T>` call.

If a _typed client_ is erroneously registered a second time as a plain Transient service, this will overwrite the registration added by the `HttpClientFactory`, breaking the link to the _named client_. It will manifest as if the `HttpClient`'s configuration is lost, as an unconfigured `HttpClient` will get injected into the _typed client_ instead.
If a _typed client_ is erroneously registered a second time as a plain Transient service, this will overwrite the registration added by the `IHttpClientFactory`, breaking the link to the _named client_. It will manifest as if the `HttpClient`'s configuration is lost, as an unconfigured `HttpClient` will get injected into the _typed client_ instead.

It might be confusing that, instead of throwing an exception, a "wrong" `HttpClient` is used. This happens because the "default" unconfigured `HttpClient` — the client with the <xref:Microsoft.Extensions.Options.Options.DefaultName?displayProperty=nameWithType> name (`string.Empty`) — is registered as a plain Transient service, to enable the most basic `HttpClientFactory` usage scenario. That's why after the link gets broken and the _typed client_ becomes just an ordinary service, this "default" `HttpClient` will naturally get injected into the respective constructor parameter.
It might be confusing that, instead of throwing an exception, a "wrong" `HttpClient` is used. This happens because the "default" unconfigured `HttpClient` — the client with the <xref:Microsoft.Extensions.Options.Options.DefaultName?displayProperty=nameWithType> name (`string.Empty`) — is registered as a plain Transient service, to enable the most basic `IHttpClientFactory` usage scenario. That's why after the link gets broken and the _typed client_ becomes just an ordinary service, this "default" `HttpClient` will naturally get injected into the respective constructor parameter.

### Different _typed clients_ are registered on a common interface

Expand All @@ -122,7 +122,7 @@ In case two different _typed clients_ are registered on a common interface, they

✔️ CONSIDER registering and configuring a _named client_ separately, and then linking it to one or multiple _typed clients_, either by specifying the name in `AddHttpClient<T>` call or by calling `AddTypedClient` during the _named client_ setup.

By design, registering and configuring a _named client_ with the same name several times just appends the configuration actions to the list of existing ones. This behavior of `HttpClientFactory` might not be obvious, but it is the same approach that is used by the [Options pattern](options.md) and configuration APIs like <xref:Microsoft.Extensions.Options.OptionsBuilder%601.Configure%2A>.
By design, registering and configuring a _named client_ with the same name several times just appends the configuration actions to the list of existing ones. This behavior of `IHttpClientFactory` might not be obvious, but it is the same approach that is used by the [Options pattern](options.md) and configuration APIs like <xref:Microsoft.Extensions.Options.OptionsBuilder%601.Configure%2A>.

This is mostly useful for advanced handler configurations, for example, adding a custom handler to a _named client_ defined externally, or mocking a primary handler for tests, but it works for `HttpClient` instance configuration as well. For example, the three following examples will result in an `HttpClient` configured in the **same** way (both `BaseAddress` and `DefaultRequestHeaders` are set):

Expand All @@ -148,7 +148,7 @@ services.AddHttpClient("example")
.ConfigureHttpClient(c => c.DefaultRequestHeaders.UserAgent.ParseAdd("HttpClient/8.0"));
```

This enables linking a _typed client_ to an already defined _named client_, and also linking several _typed clients_ to a single _named client_. It is more obvious when overloads with a `name` parameter are used:
This enables linking a _typed client_ to an already defined _named client_, and also linking several _typed clients_ to a single _named client_. It is more obvious when overloads with the `name` parameter are used:

```csharp
services.AddHttpClient("LogClient", c => c.BaseAddress = new Uri(LogServerAddress));
Expand All @@ -165,7 +165,7 @@ services.AddHttpClient("LogClient", c => c.BaseAddress = new Uri(LogServerAddres
.AddTypedClient<BarLogger>();
```

However, if you _don't_ want to reuse the same _named client_, you but you still wish to register the clients on the same interface, you can do so by explicitly specifying different names for them:
However, if you _don't_ want to reuse the same _named client_, but you still wish to register the clients on the same interface, you can do so by explicitly specifying different names for them:

```csharp
services.AddHttpClient<ITypedClient, ExampleClient>(nameof(ExampleClient),
Expand Down
Loading