Skip to content

Commit 2ffa54a

Browse files
authored
Networking breaking changes (#43351)
1 parent 8c5a7f7 commit 2ffa54a

File tree

7 files changed

+297
-3
lines changed

7 files changed

+297
-3
lines changed

docs/core/compatibility/9.0.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,13 @@ If you're migrating an app to .NET 9, the breaking changes listed here might aff
8080

8181
| Title | Type of change | Introduced version |
8282
|-----------------------------------------------------------------------------------|---------------------|--------------------|
83+
| [API obsoletions](core-libraries/9.0/obsolete-apis-with-custom-diagnostics.md) | Source incompatible | Preview 6 |
84+
| [HttpClient metrics report `server.port` unconditionally](networking/9.0/server-port-attribute.md) | Behavioral change | Preview 7 |
8385
| [HttpClientFactory logging redacts header values by default](networking/9.0/redact-headers.md) | Behavioral change | RC 1 |
86+
| [HttpClientFactory uses SocketsHttpHandler as primary handler](networking/9.0/default-handler.md) | Behavioral change | Preview 6 |
8487
| [HttpListenerRequest.UserAgent is nullable](networking/9.0/useragent-nullable.md) | Source incompatible | Preview 1 |
85-
| [API obsoletions](core-libraries/9.0/obsolete-apis-with-custom-diagnostics.md) | Source incompatible | Preview 6 |
88+
| [URI query redaction in HttpClient EventSource events](networking/9.0/query-redaction-events.md) | Behavioral change | Preview 7 |
89+
| [URI query redaction in IHttpClientFactory logs](networking/9.0/query-redaction-logs.md) | Behavioral change | Preview 7 |
8690

8791
## SDK and MSBuild
8892

docs/core/compatibility/core-libraries/6.0/obsolete-apis-with-custom-diagnostics.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ The following table lists the custom diagnostic IDs and their corresponding warn
1616

1717
| Diagnostic ID | Description | Severity |
1818
| - | - |
19-
| [SYSLIB0013](../../../../fundamentals/syslib-diagnostics/syslib0013.md) | <xref:System.Uri.EscapeUriString(System.String)?displayProperty=nameWithType> can corrupt the Uri string in some cases. Consider using <xref:System.Uri.EscapeDataString(System.String)?displayProperty=nameWithType> for query string components instead. | Warning |
19+
| [SYSLIB0013](../../../../fundamentals/syslib-diagnostics/syslib0013.md) | <xref:System.Uri.EscapeUriString(System.String)?displayProperty=nameWithType> can corrupt the URI string in some cases. Consider using <xref:System.Uri.EscapeDataString(System.String)?displayProperty=nameWithType> for query string components instead. | Warning |
2020
| [SYSLIB0014](../../../../fundamentals/syslib-diagnostics/syslib0014.md) | <xref:System.Net.WebRequest>, <xref:System.Net.HttpWebRequest>, <xref:System.Net.ServicePoint>, and <xref:System.Net.WebClient> are obsolete. Use <xref:System.Net.Http.HttpClient> instead. | Warning |
2121
| [SYSLIB0015](../../../../fundamentals/syslib-diagnostics/syslib0015.md) | <xref:System.Runtime.CompilerServices.DisablePrivateReflectionAttribute> has no effect in .NET 6+. | Warning |
2222
| [SYSLIB0016](../../../../fundamentals/syslib-diagnostics/syslib0016.md) | Use the <xref:System.Drawing.Graphics.GetContextInfo%2A?displayProperty=nameWithType> overloads that accept arguments for better performance and fewer allocations. | Warning |
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
title: "HttpClientFactory uses SocketsHttpHandler as primary handler"
3+
description: Learn about the breaking change in networking in .NET 9 where HttpClientFactory now uses SocketsHttpHandler as the default primary handler.
4+
ms.date: 11/5/2024
5+
---
6+
7+
# HttpClientFactory uses SocketsHttpHandler as primary handler
8+
9+
`HttpClientFactory` allows you to configure an <xref:System.Net.Http.HttpMessageHandler> pipeline for named and typed <xref:System.Net.Http.HttpClient> objects. The inner-most handler, or the one that actually sends the request on the wire, is called a *primary handler*. If not configured, this handler was previously always an <xref:System.Net.Http.HttpClientHandler>. While the default primary handler is an implementation detail, there were users who depended on it. For example, some users cast the primary handler to `HttpClientHandler` to set properties like <xref:System.Net.Http.HttpClientHandler.ClientCertificates>, <xref:System.Net.Http.HttpClientHandler.UseCookies>, and <xref:System.Net.Http.HttpClientHandler.UseProxy>.
10+
11+
With this change, the default primary handler is a <xref:System.Net.Http.SocketsHttpHandler> on platforms that support it. On other platforms, for example, .NET Framework, <xref:System.Net.Http.HttpClientHandler> continues to be used.
12+
13+
`SocketsHttpHandler` now also has the <xref:System.Net.Http.SocketsHttpHandler.PooledConnectionLifetime> property preset to match the <xref:Microsoft.Extensions.Http.HttpClientFactoryOptions.HandlerLifetime> value. (It reflects the latest value, if `HandlerLifetime` was configured by the user).
14+
15+
## Version introduced
16+
17+
.NET 9 Preview 6
18+
19+
## Previous behavior
20+
21+
The default primary handler was `HttpClientHandler`. Casting it to `HttpClientHandler` to update the properties happened to work.
22+
23+
```csharp
24+
services.AddHttpClient("test")
25+
.ConfigurePrimaryHttpMessageHandler((h, _) =>
26+
{
27+
((HttpClientHandler)h).UseCookies = false;
28+
});
29+
30+
// This worked.
31+
var client = httpClientFactory.CreateClient("test");
32+
```
33+
34+
## New behavior
35+
36+
On platforms where `SocketsHttpHandler` is supported, the default primary handler is now `SocketsHttpHandler` with `PooledConnectionLifetime` set to the `HandlerLifetime` value. Casting it to `HttpClientHandler` to update the properties throws an <xref:System.InvalidCastException>.
37+
38+
For example, the same code from the [Previous behavior](#previous-behavior) section now throws an <xref:System.InvalidCastException>:
39+
40+
> System.InvalidCastException: Unable to cast object of type 'System.Net.Http.SocketsHttpHandler' to type 'System.Net.Http.HttpClientHandler'.
41+
42+
## Type of breaking change
43+
44+
This change is a [behavioral change](../../categories.md#behavioral-change).
45+
46+
## Reason for change
47+
48+
One of the most common problems `HttpClientFactory` users run into is when a `Named` or `Typed` client erroneously gets captured in a singleton service, or, in general, stored somewhere for a period of time that's longer than the specified <xref:Microsoft.Extensions.Http.HttpClientFactoryOptions.HandlerLifetime>. Because `HttpClientFactory` can't rotate such handlers, they might end up not respecting DNS changes.
49+
50+
This problem can be mitigated by using <xref:System.Net.Http.SocketsHttpHandler>, which has an option to control <xref:System.Net.Http.SocketsHttpHandler.PooledConnectionLifetime>. Similarly to <xref:Microsoft.Extensions.Http.HttpClientFactoryOptions.HandlerLifetime>, the pooled connection lifetime allows regularly recreating connections to pick up DNS changes, but on a lower level. A client with `PooledConnectionLifetime` set up can be safely used as a singleton.
51+
52+
It is, unfortunately, easy and seemingly "intuitive" to inject a `Typed` client into a singleton. But it's hard to have any kind of check or analyzer to make sure `HttpClient` isn't captured when it wasn't supposed to be captured. It's also hard to troubleshoot the resulting issues. So as a preventative measure&mdash;to minimize the potential impact of erroneous usage patterns&mdash;the `SocketsHttpHandler` mitigation is now applied by default.
53+
54+
This change only affects cases when the client wasn't configured by the end user to use a custom <xref:Microsoft.Extensions.Http.HttpMessageHandlerBuilder.PrimaryHandler> (for example, via <xref:Microsoft.Extensions.DependencyInjection.HttpClientBuilderExtensions.ConfigurePrimaryHttpMessageHandler``1(Microsoft.Extensions.DependencyInjection.IHttpClientBuilder)>).
55+
56+
## Recommended action
57+
58+
There are three options to work around the breaking change:
59+
60+
- Explicitly specify and configure a primary handler for each of your clients:
61+
62+
```csharp
63+
services.AddHttpClient("test")
64+
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { UseCookies = false });
65+
```
66+
67+
- Overwrite the default primary handler for all clients using <xref:Microsoft.Extensions.DependencyInjection.HttpClientFactoryServiceCollectionExtensions.ConfigureHttpClientDefaults(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Action{Microsoft.Extensions.DependencyInjection.IHttpClientBuilder})>:
68+
69+
```csharp
70+
services.ConfigureHttpClientDefaults(b =>
71+
b.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { UseCookies = false }));
72+
```
73+
74+
- In the configuration action, check for both `HttpClientHandler` and `SocketsHttpHandler`:
75+
76+
```csharp
77+
services.AddHttpClient("test")
78+
.ConfigurePrimaryHttpMessageHandler((h, _) =>
79+
{
80+
if (h is HttpClientHandler hch)
81+
{
82+
hch.UseCookies = false;
83+
}
84+
85+
if (h is SocketsHttpHandler shh)
86+
{
87+
shh.UseCookies = false;
88+
}
89+
});
90+
```
91+
92+
## Affected APIs
93+
94+
- <xref:Microsoft.Extensions.Http.HttpMessageHandlerBuilder.PrimaryHandler?displayProperty=fullName>
95+
- <xref:Microsoft.Extensions.DependencyInjection.HttpClientBuilderExtensions.ConfigurePrimaryHttpMessageHandler(Microsoft.Extensions.DependencyInjection.IHttpClientBuilder,System.Action{System.Net.Http.HttpMessageHandler,System.IServiceProvider})?displayProperty=fullName>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
title: "URI query redaction in HttpClient EventSource events"
3+
description: "Learn about the breaking change in networking in .NET 9 where HttpClient EventSource events scrub query strings by default to enhance privacy."
4+
ms.date: 11/5/2024
5+
ai-usage: ai-assisted
6+
---
7+
8+
# URI query redaction in HttpClient EventSource events
9+
10+
In .NET 9, the default behavior of <xref:System.Diagnostics.Tracing.EventSource> events emitted by <xref:System.Net.Http.HttpClient> and <xref:System.Net.Http.SocketsHttpHandler> (`EventSource` name: `System.Net.Http`) has been modified to scrub query strings. This change enhances privacy by preventing the logging of potentially sensitive information contained in query strings. If necessary, you can override this behavior.
11+
12+
## Version introduced
13+
14+
.NET 9 Preview 7
15+
16+
## Previous behavior
17+
18+
Previously, events emitted by `HttpClient` and `SocketsHttpHandler` included query string information, which could inadvertently expose sensitive information.
19+
20+
## New behavior
21+
22+
With the change in [dotnet/runtime#104741](https://github.com/dotnet/runtime/pull/104741), query strings are replaced by a `*` character in `HttpClient` and `SocketsHttpHandler` events, by default. This change affects specific events and parameters such as `pathAndQuery` in `RequestStart` and `redirectUri` in `Redirect`.
23+
24+
## Type of breaking change
25+
26+
This change is a [behavioral change](../../categories.md#behavioral-change).
27+
28+
## Reason for change
29+
30+
The primary reason for this change was to enhance privacy by reducing the risk of sensitive information being logged inadvertently. Query strings often contain sensitive data, and redacting them from logs by default helps protect this information.
31+
32+
## Recommended action
33+
34+
If you need query string information when consuming `HttpClient` or `SocketsHttpHandler` events and you're confident that it's safe to do so, you can enable query string logging globally by setting an AppContext switch in one of three ways:
35+
36+
- In the project file.
37+
38+
```xml
39+
<ItemGroup>
40+
<RuntimeHostConfigurationOption Include="System.Net.Http.DisableUriRedaction" Value="true" />
41+
</ItemGroup>
42+
```
43+
44+
- In the *runtimeconfig.json* file.
45+
46+
```json
47+
{
48+
"runtimeOptions": {
49+
"configProperties": {
50+
"System.Net.Http.DisableUriRedaction": true
51+
}
52+
}
53+
}
54+
```
55+
56+
- Through an environment variable.
57+
58+
Set `DOTNET_SYSTEM_NET_HTTP_DISABLEURIREDACTION` to `true` or 1.
59+
60+
Otherwise, no action is required, and the default behavior will help enhance the privacy aspects of your application.
61+
62+
> [!NOTE]
63+
> This switch also disables query string redaction in the default `IHttpClientFactory` logs. For more information, see [URI query redaction in IHttpClientFactory logs](query-redaction-logs.md).
64+
65+
## Affected APIs
66+
67+
- [System.Net.Http.SocketsHttpHandler.Send](xref:System.Net.Http.HttpMessageHandler.Send(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken))
68+
- [System.Net.Http.SocketsHttpHandler.SendAsync](xref:System.Net.Http.HttpMessageHandler.SendAsync(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken))
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
title: "URI query redaction in IHttpClientFactory logs"
3+
description: Learn about the breaking change in networking in .NET 9 where the IHttpClientFactory implementation scrubs query strings in logs to enhance privacy.
4+
ms.date: 11/5/2024
5+
ai-usage: ai-assisted
6+
---
7+
8+
# URI query redaction in IHttpClientFactory logs
9+
10+
In .NET 9, the default implementation of <xref:System.Net.Http.IHttpClientFactory> has been modified to scrub query strings when logging URI information. This change enhances privacy by preventing the logging of potentially sensitive information contained in query strings. For scenarios where logging query strings is necessary and deemed safe, you can override this behavior.
11+
12+
## Version introduced
13+
14+
.NET 9 Preview 7
15+
16+
## Previous behavior
17+
18+
Previously, the default implementation of `IHttpClientFactory` logging included query strings in the messages passed to <xref:Microsoft.Extensions.Logging.ILogger>, which could inadvertently expose sensitive information.
19+
20+
## New behavior
21+
22+
The messages passed to <xref:Microsoft.Extensions.Logging.ILogger> now have query strings replaced by a `*` character.
23+
24+
## Type of breaking change
25+
26+
This change is a [behavioral change](../../categories.md#behavioral-change).
27+
28+
## Reason for change
29+
30+
The primary reason for this change is to enhance privacy by reducing the risk of sensitive information being logged inadvertently. Query strings often contain sensitive data and excluding them from logs by default helps protect this information.
31+
32+
## Recommended action
33+
34+
If your application relies on logging query strings and you're confident that it's safe to do so, you can enable query string logging globally by setting an AppContext switch in one of three ways:
35+
36+
- In the project file.
37+
38+
```xml
39+
<ItemGroup>
40+
<RuntimeHostConfigurationOption Include="System.Net.Http.DisableUriRedaction" Value="true" />
41+
</ItemGroup>
42+
```
43+
44+
- In the *runtimeconfig.json* file.
45+
46+
```json
47+
{
48+
"runtimeOptions": {
49+
"configProperties": {
50+
"System.Net.Http.DisableUriRedaction": true
51+
}
52+
}
53+
}
54+
```
55+
56+
- Through an environment variable.
57+
58+
Set `DOTNET_SYSTEM_NET_HTTP_DISABLEURIREDACTION` to `true` or 1.
59+
60+
Otherwise, no action is required, and the default behavior will help enhance the privacy aspects of your application.
61+
62+
> [!NOTE]
63+
> This switch also disables query string redaction in `HttpClient` EventSource events. For more information, see [URI query redaction in HttpClient EventSource events](query-redaction-events.md).
64+
65+
## Affected APIs
66+
67+
- <xref:Microsoft.Extensions.DependencyInjection.HttpClientFactoryServiceCollectionExtensions.AddHttpClient*?displayProperty=fullName>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
title: "HttpClient metrics report `server.port` unconditionally"
3+
description: Learn about the breaking change in networking in .NET 9 where HttpClient metrics now report the `server.port` attribute unconditionally to maintain compliance with Open Telemetry standards.
4+
ms.date: 11/5/2024
5+
---
6+
7+
# HttpClient metrics report `server.port` unconditionally
8+
9+
When [HttpClient metrics](../../../../fundamentals/networking/telemetry/metrics.md) were added in .NET 8, `server.port` was introduced as a [`Conditionally Required`](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/#conditionally-required) attribute in accordance with the state of the standard at that time. Being conditionally required meant that the port was only reported if it did not match the default port of the corresponding protocol (80 for HTTP, 443 for HTTPS). However, the standard [requirement level of the attribute](https://opentelemetry.io/docs/specs/semconv/http/http-spans/#http-client) has since been changed to `Required`.
10+
11+
To maintain compliance with the Open Telemetry standard while keeping the instrument's behaviors consistent with each other, the instruments `http.client.request.duration`, `http.client.connection.duration`, and `http.client.open_connections` have been changed to unconditionally report the `server.port` attribute.
12+
13+
This change can break existing queries in monitoring software like Prometheus.
14+
15+
## Version introduced
16+
17+
.NET 9 Preview 7
18+
19+
## Previous behavior
20+
21+
`http.client.request.duration`, `http.client.connection.duration`, and `http.client.open_connections` reported the `server.port` attribute only if it did not match the corresponding protocol's default port (80 for HTTP, 443 for HTTPS).
22+
23+
## New behavior
24+
25+
The `server.port` attribute is now unconditionally reported by the instruments `http.client.request.duration`, `http.client.connection.duration`, and `http.client.open_connections`.
26+
27+
## Type of breaking change
28+
29+
This change is a [behavioral change](../../categories.md#behavioral-change).
30+
31+
## Reason for change
32+
33+
The change maintains compliance with the [Open Telemetry specification](https://opentelemetry.io/docs/specs/semconv/http/http-spans/#http-client) while keeping `HttpClient` instruments consistent with each other.
34+
35+
## Recommended action
36+
37+
No action is needed if you don't rely on [HttpClient metrics](../../../../fundamentals/networking/telemetry/metrics.md). If you use the `http.client.request.duration`, `http.client.connection.duration`, or `http.client.open_connections` instruments, this change might break existing queries in monitoring software like Prometheus.
38+
39+
## Affected APIs
40+
41+
- `System.Net.Http.SocketsHttpHandler.Send(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken)`
42+
- `System.Net.Http.SocketsHttpHandler.SendAsync(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken)`
43+
- <xref:System.Net.Http.HttpClientHandler.Send(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken)?displayProperty=fullName>
44+
- <xref:System.Net.Http.HttpClientHandler.SendAsync(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken)?displayProperty=fullName>

0 commit comments

Comments
 (0)