Introduction : pourquoi un client HTTP correct en C# ?
Dans le développement moderne, pratiquement aucune application ne peut se passer d'interagir avec des services externes. Qu'il s'agisse d'envoyer des données à un serveur, d'obtenir le taux de change ou de travailler avec une API cloud, tout cela nécessite une implémentation correcte des requêtes HTTP. Dans l'écosystème C# (.NET), l'outil principal pour cette tâche est la classe HttpClient. Cependant, de nombreux développeurs, en particulier les débutants, commettent des erreurs typiques : créer une nouvelle instance de HttpClient pour chaque requête, oublier de gérer les exceptions ou mal travailler avec l'asynchronisme.
Dans cet article, nous allons voir comment organiser correctement un client HTTP en C#, examiner l'envoi de requêtes GET et POST, la gestion des en-têtes et du corps de la requête, ainsi que les bonnes pratiques de gestion des erreurs. Après avoir lu cet article, vous serez en mesure d'écrire un code fiable et performant pour interagir avec n'importe quelle API REST.
Fondamentaux du travail avec HttpClient en C#
La classe HttpClient fait partie de l'espace de noms System.Net.Http et est disponible dans toutes les versions modernes de .NET (Core, 5, 6, 7, 8 et supérieures). Son principal avantage est la prise en charge des opérations asynchrones et la gestion automatique du pool de connexions.
Création correcte de HttpClient
Règle la plus importante : ne créez pas un nouveau HttpClient pour chaque requête. Cela peut entraîner un épuisement des sockets (socket exhaustion). Utilisez plutôt une seule instance pour toute la durée de vie de l'application ou utilisez IHttpClientFactory.
// ❌ Mauvais : nouveau HttpClient pour chaque requête
using (var client = new HttpClient())
{
var response = await client.GetAsync("https://api.example.com");
}
// ✅ Bon : un seul HttpClient pour toutes les requêtes
public class MyHttpService
{
private static readonly HttpClient _client = new HttpClient();
public async Task<string> GetDataAsync(string url)
{
return await _client.GetStringAsync(url);
}
}
Paramètres de base
Lors de l'initialisation de HttpClient, vous pouvez définir l'adresse de base, les délais d'attente et les en-têtes par défaut :
public class ApiClient
{
private readonly HttpClient _httpClient;
public ApiClient()
{
_httpClient = new HttpClient
{
BaseAddress = new Uri("https://api.pythonlib.ru/"),
Timeout = TimeSpan.FromSeconds(10)
};
// En-têtes qui seront envoyés avec chaque requête
_httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
_httpClient.DefaultRequestHeaders.Add("User-Agent", "MyApp/1.0");
}
}
Envoi de requêtes GET et POST
Examinons les deux types de requêtes HTTP les plus courants : la récupération de données (GET) et l'envoi de données (POST).
Requête GET : récupération de données
Une requête GET est utilisée pour lire des données depuis le serveur. Elle ne doit pas modifier l'état de la ressource et ne contient pas de corps.
public async Task<string> GetUserAsync(int userId)
{
try
{
var response = await _httpClient.GetAsync($"/api/users/{userId}");
response.EnsureSuccessStatusCode(); // Lèvera une exception en cas d'erreur
return await response.Content.ReadAsStringAsync();
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Erreur de requête : {ex.Message}");
throw;
}
}
Pour les cas simples, vous pouvez utiliser la forme abrégée :
string json = await _httpClient.GetStringAsync("/api/users/42");
Requête POST : envoi de données
Une requête POST est utilisée pour créer de nouvelles ressources. Les données sont transmises dans le corps de la requête, le plus souvent au format JSON.
public async Task<User> CreateUserAsync(User newUser)
{
// Sérialiser l'objet en JSON
var json = JsonSerializer.Serialize(newUser);