API Design
HttpClient provides a cleaner, more intuitive API compared to WebRequest. The framework encapsulates HTTP request components—methods, URLs, headers, and body content—into dedicated objects, streamlining development.
Sending a GET request with HttpClient requires a single call to GetAsync(url), while POST requests use PostAsync(url, content). In contrast, WebRequest demands manual configuration of request objects, HTTP methods, headers, and request body writing, resulting in more verbose code.
Asynchronous Programming Support
HttpClient offers native async/await support through dedicated *Async methods, enabling straightforward non-blocking operations that enhance application responsiveness.
WebRequest supports asynchronous patterns too, but relies on callback functions or Begin/End method pairs, making the code less readable and harder to maintain.
Performance Characteristics
HttpClient leverages connection pooling internally, minimizing connection establishment and teardown overhead. This design typically delivers superior throughput compared to WebRequest.
WebRequest lacks these optimizations, which can result in slower performance under load.
Configuration Flexibility
HttpClient provides extensive configuration options including timeout settings, proxy configuration, and cookie containers. While WebRequest offers some configurability, it falls short in flexibility.
Implementation Examples
GET Requests
Using HttpClient:
using System.Net.Http;
using System.Threading.Tasks;
public async Task<string> FetchDataAsync(string endpoint)
{
using var httpClient = new HttpClient();
using var httpResponse = await httpClient.GetAsync(endpoint);
httpResponse.EnsureSuccessStatusCode();
return await httpResponse.Content.ReadAsStringAsync();
}
Using WebRequest:
using System.Net;
using System.IO;
using System.Threading.Tasks;
public async Task<string> FetchDataAsync(string endpoint)
{
var request = WebRequest.Create(endpoint);
request.Method = HttpMethod.Get.Method;
using var response = await request.GetResponseAsync();
using var responseStream = response.GetResponseStream();
using var reader = new StreamReader(responseStream);
return reader.ReadToEnd();
}
POST Requests
Using HttpClient:
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
public async Task<string> SubmitDataAsync(string endpoint, string payload)
{
using var httpClient = new HttpClient();
var requestBody = new StringContent(payload, Encoding.UTF8, "application/json");
using var response = await httpClient.PostAsync(endpoint, requestBody);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
// Usage
string apiEndpoint = "https://api.example.com/resource";
string jsonPayload = "{\"username\":\"john\",\"active\":true}";
string responseData = await SubmitDataAsync(apiEndpoint, jsonPayload);
Console.WriteLine(responseData);
Key Points:
StringContentconstructor accepts the data string, encoding, and MIME type for automatic Content-Type header settingEnsureSuccessStatusCode()throws an exception for non-success status codesReadAsStringAsync()converts the response body to a string
Using WebRequest:
using System.Net;
using System.IO;
using System.Text;
using System.Threading.Tasks;
public async Task<string> SubmitDataAsync(string endpoint, string payload)
{
var request = WebRequest.Create(endpoint);
request.Method = HttpMethod.Post.Method;
request.ContentType = "application/json";
using (var requestStream = await request.GetRequestStreamAsync())
using (var writer = new StreamWriter(requestStream))
{
await writer.WriteAsync(payload);
}
using var response = await request.GetResponseAsync();
using var responseStream = response.GetResponseStream();
using var reader = new StreamReader(responseStream);
return reader.ReadToEnd();
}
// Usage
string apiEndpoint = "https://api.example.com/resource";
string jsonPayload = "{\"username\":\"john\",\"active\":true}";
string responseData = await SubmitDataAsync(apiEndpoint, jsonPayload);
Console.WriteLine(responseData);
Key Points:
- Manual request stream acquisition with
GetRequestStreamAsync() - Explicit Content-Type assignment before writing data
- Sequential stream operations for sending and receiving data
Recommendations
Perfer HttpClient for most HTTP communication scenarios due to its modern API and superior performance characteristics.
Reserve WebRequest for specific use cases requiring legacy system compatibility or specialized configuration not available in HttpClient.
When using HttpClient, employ using declarations or statements to ensure proper resource cleanup and prevent memory leaks.
Select appropriate content types (JSON, XML, form data) and configure the corresponding Content-Type headers accordingly for proper request formatting.