If you call HttpClient.GetAsync
or HttpClient.PostAsync
and then await
the result, does the await
wait only for the headers to be received, or does it wait for the body to be received? Let's find out!
Our simple server
We will create a simple server that sends a response with a header and a body. The body will be sent in chunks so we can see when it is received.
app.MapGet("/", async context =>
{
await context.Response.WriteAsync("1");
await Task.Delay(500);
await context.Response.WriteAsync("2");
await Task.Delay(500);
await context.Response.WriteAsync("3");
await context.Response.CompleteAsync();
});
So, the whole request takes at least 1 second to complete. So, let's write a very simple call to that endpoint
The client
using var client = new HttpClient();
// Let's measure the time it takes to get the response
var sw = Stopwatch.StartNew();
await client.GetAsync("https://localhost:5001");
Console.WriteLine($"Response-Time: {sw.ElapsedMilliseconds}ms");
If we execute this code, we will see that the response time is around 1 second. So the await
waits for the whole response to be received:
Response-Time: 1088ms
Now that we answered the question, let's see how we can actually not await the body! We can use the HttpCompletionOption.ResponseHeadersRead
option:
var sw = Stopwatch.StartNew();
await client.GetAsync("https://localhost:5001", HttpCompletionOption.ResponseHeadersRead);
Console.WriteLine($"Response-Time: {sw.ElapsedMilliseconds}ms");
So we added the HttpCompletionOption.ResponseHeadersRead
flag to the GetAsync
call. Now the response time is much lower:
Response-Time: 78ms
So the await
only waits for the headers to be received. The body is still being received in the background. If you want to wait for the body to be received, you can use the ReadAsStringAsync
method:
using var response = await client.GetAsync("https://localhost:5001", HttpCompletionOption.ResponseHeadersRead);
var body = await response.Content.ReadAsStringAsync();
Now very important is that we are using using var response
- the object is maybe still holding on to resources, so we should dispose it as soon as possible. If you omit the HttpCompletionOption.ResponseHeadersRead
flag, the response
object will be disposed when the await
is done, so you don't have to worry about it.
All in all, there is a performance and memory benefit when using HttpCompletionOption.ResponseHeadersRead
, and you can still read the body if you want to. But you have to be careful with the response
object, as it might still hold on to resources and your code becomes more complex. So this shouldn't be your default choice, but only if you really need it.