HttpClient improvements in .NET 10

4/28/2025
5 minute read

New dotnet version means new features and improvements. There is a nice update to the HttpClient class in .NET 10.

Content buffering

To understand the improvement, we have to distinguish between two types:

  • We know upfront how much data we will receive (so the Content-Length header is set).
  • We don't know how much data we will receive (so the Content-Length header is not set).

The improvement is for the latter case. When streaming a response, it can happen that the buffer has to be resized multiple times. This can be expensive, especially if the response is large. The new HttpClient implementation in .NET 10 uses a pooled approach to reduce the overhead or creating new buffers.

Here are some of the improvements (details see: https://github.com/dotnet/runtime/pull/109642):

| Method            | Toolchain | Length     | Mean             | Ratio | Allocated     | Alloc Ratio |
|------------------|-----------|------------|------------------|-------|----------------|--------------|
| GetByteArrayAsync| main      | 10000      | 1,114.6 ns       | 1.00  | 10.81 KB       | 1.00         |
| GetByteArrayAsync| pr        | 10000      | 994.3 ns         | 0.89  | 10.84 KB       | 1.00         |
| GetAsync         | main      | 10000      | 1,284.7 ns       | 1.00  | 28.93 KB       | 1.00         |
| GetAsync         | pr        | 10000      | 1,018.1 ns       | 0.79  | 10.84 KB       | 0.37         |
| GetByteArrayAsync| main      | 100000     | 28,454.2 ns      | 1.00  | 98.73 KB       | 1.00         |
| GetByteArrayAsync| pr        | 100000     | 28,038.7 ns      | 0.99  | 98.76 KB       | 1.00         |
| GetAsync         | main      | 100000     | 31,313.5 ns      | 1.00  | 251.58 KB      | 1.00         |
| GetAsync         | pr        | 100000     | 28,186.0 ns      | 0.90  | 98.76 KB       | 0.39         |
| GetByteArrayAsync| main      | 1000000    | 127,633.7 ns     | 1.00  | 978.16 KB      | 1.00         |
| GetByteArrayAsync| pr        | 1000000    | 110,941.5 ns     | 0.87  | 978.11 KB      | 1.00         |
| GetAsync         | main      | 1000000    | 151,716.7 ns     | 1.00  | 2032.28 KB     | 1.00         |
| GetAsync         | pr        | 1000000    | 110,231.7 ns     | 0.73  | 978.1 KB       | 0.48         |
| GetByteArrayAsync| main      | 10000000   | 1,946,940.2 ns   | 1.00  | 9768.06 KB     | 1.00         |
| GetByteArrayAsync| pr        | 10000000   | 1,113,033.0 ns   | 0.57  | 9769.06 KB     | 1.00         |
| GetAsync         | main      | 10000000   | 2,720,321.2 ns   | 1.04  | 32553.84 KB    | 1.00         |
| GetAsync         | pr        | 10000000   | 1,137,477.7 ns   | 0.43  | 9768.88 KB     | 0.30         |
| GetByteArrayAsync| main      | 100000000  | 21,216,153.0 ns  | 1.00  | 97657.44 KB    | 1.00         |
| GetByteArrayAsync| pr        | 100000000  | 17,026,034.7 ns  | 0.80  | 97657.69 KB    | 1.00         |
| GetAsync         | main      | 100000000  | 25,177,538.4 ns  | 1.00  | 260446.05 KB   | 1.00         |
| GetAsync         | pr        | 100000000  | 16,487,114.6 ns  | 0.66  | 97657.69 KB    | 0.37         |
An error has occurred. This application may no longer respond until reloaded. Reload x