The HttpRequestMessage
class is a fundamental component of the HttpClient
API that encapsulates all the information needed to send an HTTP request. Part of the System.Net.Http
namespace, this class provides fine-grained control over HTTP requests, making it ideal for advanced scenarios where you need more flexibility than the simplified HttpClient
methods offer.
Purpose and Core Functionality
The HttpRequestMessage
class serves as a complete representation of an HTTP request, including:
- HTTP method (GET, POST, PUT, DELETE, etc.)
- Request URI
- HTTP headers
- Request content/body
- HTTP version and other configuration options
Key Properties and Capabilities
1. HTTP Method Control
Set the HTTP method using the Method
property:
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.example.com/users");
// Or using custom methods
request.Method = new HttpMethod("PATCH");
2. Request URI Management
Configure the target URI with the RequestUri
property:
request.RequestUri = new Uri("https://api.example.com/users/123");
3. Header Customization
Add custom headers through the Headers
property:
request.Headers.Add("Authorization", "Bearer your-token-here");
request.Headers.Add("User-Agent", "MyApp/1.0");
request.Headers.Add("X-Custom-Header", "custom-value");
4. Content Handling
Set request body content using the Content
property:
var jsonContent = new StringContent(
JsonSerializer.Serialize(userData),
Encoding.UTF8,
"application/json"
);
request.Content = jsonContent;
Practical Examples
Basic GET Request with Custom Headers
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class ApiClient
{
private readonly HttpClient _httpClient;
public ApiClient()
{
_httpClient = new HttpClient();
}
public async Task<string> GetDataAsync()
{
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.example.com/data");
// Add custom headers
request.Headers.Add("Accept", "application/json");
request.Headers.Add("Authorization", "Bearer your-token");
request.Headers.Add("User-Agent", "MyApp/1.0");
try
{
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Request failed: {ex.Message}");
throw;
}
}
}
POST Request with JSON Content
public async Task<HttpResponseMessage> CreateUserAsync(User user)
{
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.example.com/users");
// Set JSON content
var json = JsonSerializer.Serialize(user);
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
// Add headers
request.Headers.Add("Accept", "application/json");
request.Headers.Add("Authorization", "Bearer your-token");
return await _httpClient.SendAsync(request);
}
Advanced Configuration with Timeout and Cancellation
public async Task<string> GetWithTimeoutAsync(CancellationToken cancellationToken = default)
{
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.example.com/slow-endpoint");
// Configure request options
request.Headers.Add("Accept", "application/json");
request.Version = HttpVersion.Version20; // Use HTTP/2
// Add custom properties for logging or tracking
request.Options.Set(new HttpRequestOptionsKey<string>("RequestId"), Guid.NewGuid().ToString());
try
{
using var response = await _httpClient.SendAsync(request, cancellationToken);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync(cancellationToken);
}
catch (OperationCanceledException)
{
Console.WriteLine("Request was cancelled");
throw;
}
}
Multipart Form Data Example
public async Task<HttpResponseMessage> UploadFileAsync(string filePath, Dictionary<string, string> formData)
{
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.example.com/upload");
using var multipartContent = new MultipartFormDataContent();
// Add form fields
foreach (var kvp in formData)
{
multipartContent.Add(new StringContent(kvp.Value), kvp.Key);
}
// Add file
var fileContent = new ByteArrayContent(await File.ReadAllBytesAsync(filePath));
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
multipartContent.Add(fileContent, "file", Path.GetFileName(filePath));
request.Content = multipartContent;
request.Headers.Add("Authorization", "Bearer your-token");
return await _httpClient.SendAsync(request);
}
When to Use HttpRequestMessage
Use HttpRequestMessage
when you need:
- Custom Headers: Adding authorization tokens, API keys, or custom headers
- Complex Content: Sending multipart data, custom content types, or binary data
- HTTP Method Flexibility: Using methods beyond GET/POST or custom HTTP methods
- Request Metadata: Adding properties for logging, tracking, or middleware processing
- Fine-grained Control: Specifying HTTP version, timeout behavior, or other advanced options
For simple scenarios, the convenience methods like GetAsync()
, PostAsync()
, and PutAsync()
are perfectly adequate. However, when you need the full power and flexibility of HTTP request configuration, HttpRequestMessage
is the appropriate choice.
Best Practices
- Reuse HttpClient: Create one
HttpClient
instance and reuse it for multiple requests - Dispose Properly: Use
using
statements or implementIDisposable
patterns - Handle Exceptions: Always wrap HTTP calls in try-catch blocks
- Use Cancellation Tokens: Support request cancellation for better resource management
- Configure Timeouts: Set appropriate timeouts for your use case
The HttpRequestMessage
class provides the foundation for building robust, configurable HTTP clients in C# applications, offering the flexibility needed for complex API integrations and web scraping scenarios.