HTTP headers
asynchronous request
WebClient
programming
web development

Get HTTP headers in asynchronous WebClient request

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

With WebClient, request headers are set before the async call starts, and response headers become available after the request completes. That makes the main pattern straightforward: configure Headers, await the asynchronous operation, then read ResponseHeaders. The bigger caveat is that WebClient is legacy API surface, so this is mainly a maintenance topic rather than the preferred design for new .NET code.

Set Request Headers Before Starting the Call

WebClient exposes a Headers collection for outgoing headers.

csharp
1using System;
2using System.Net;
3using System.Threading.Tasks;
4
5public static async Task RunAsync()
6{
7    using var client = new WebClient();
8    client.Headers[HttpRequestHeader.Accept] = "application/json";
9    client.Headers[HttpRequestHeader.UserAgent] = "LegacyClient/1.0";
10
11    string body = await client.DownloadStringTaskAsync("https://example.com");
12    Console.WriteLine(body.Length);
13}

Those headers are part of the outgoing request. They must be set before calling DownloadStringTaskAsync, OpenReadTaskAsync, or another async method.

Read Response Headers After the Await

Once the asynchronous request completes, ResponseHeaders is populated with the server's returned headers.

csharp
1using System;
2using System.Net;
3using System.Threading.Tasks;
4
5public static async Task RunAsync()
6{
7    using var client = new WebClient();
8    string body = await client.DownloadStringTaskAsync("https://example.com");
9
10    WebHeaderCollection headers = client.ResponseHeaders;
11    Console.WriteLine(headers[HttpResponseHeader.ContentType]);
12    Console.WriteLine(headers["Server"]);
13}

The important timing rule is simple: do not expect ResponseHeaders to contain the final response until the request has actually finished.

Handle Errors Without Losing Header Context

If the request fails with a WebException, you may still be able to inspect the response headers from the exception response.

csharp
1using System;
2using System.IO;
3using System.Net;
4using System.Threading.Tasks;
5
6public static async Task RunAsync()
7{
8    using var client = new WebClient();
9
10    try
11    {
12        await client.DownloadStringTaskAsync("https://example.com/missing");
13    }
14    catch (WebException ex) when (ex.Response is HttpWebResponse response)
15    {
16        Console.WriteLine((int)response.StatusCode);
17        Console.WriteLine(response.Headers[HttpResponseHeader.ContentType]);
18
19        using var reader = new StreamReader(response.GetResponseStream());
20        Console.WriteLine(await reader.ReadToEndAsync());
21    }
22}

This matters because real HTTP work often requires both the error status and the headers that came back with it.

Understand the Limits of WebClient

WebClient is convenient for simple tasks, but it has limits:

  • limited control compared with HttpClient
  • awkward timeout customization
  • no first-class cancellation tokens in the modern style
  • legacy event and task patterns mixed together

If your only requirement is to read response headers in an existing codebase, WebClient can still do the job. If you are designing new networking code, HttpClient is usually the better tool.

A Modern Equivalent With HttpClient

For comparison, this is how the same idea looks with HttpClient.

csharp
1using System;
2using System.Net.Http;
3using System.Threading.Tasks;
4
5public static async Task RunAsync()
6{
7    using var client = new HttpClient();
8    client.DefaultRequestHeaders.Add("User-Agent", "ModernClient/1.0");
9
10    using var response = await client.GetAsync("https://example.com");
11    Console.WriteLine(response.Headers.Server);
12    Console.WriteLine(response.Content.Headers.ContentType);
13}

This is not required to answer the original WebClient question, but it explains why most new code has moved away from WebClient.

Common Pitfalls

The most common mistake is reading ResponseHeaders before the async operation has completed.

Another mistake is confusing request headers with response headers. client.Headers configures what you send, while client.ResponseHeaders exposes what you received.

A third issue is forgetting that failed requests may still return useful response metadata through the exception response.

Finally, do not keep extending WebClient for modern HTTP needs if HttpClient would solve the problem more cleanly.

Summary

  • Set outgoing headers on WebClient.Headers before starting the async request.
  • Read incoming headers from WebClient.ResponseHeaders after the request completes.
  • On errors, inspect WebException.Response to recover status and headers.
  • 'WebClient can handle simple header access, but it is legacy API surface.'
  • 'HttpClient is usually the better choice for new code.'
  • The key timing rule is that response headers are only reliable after the async operation has finished.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.