Networking en C# (TcpClient, HttpClient, appels REST API)
Apprenez le networking en C# avec TcpClient, HttpClient et les appels REST API pour gérer les échanges de données.
Dans les applications modernes, la communication réseau joue un rôle essentiel.
En C#, il est possible de communiquer à la fois avec des sockets TCP de bas niveau et avec des appels HTTP/REST API de haut niveau.
.NET fournit des classes puissantes pour cela : TcpClient, TcpListener et HttpClient.
Cet article présente étape par étape des exemples allant de la programmation réseau de base aux appels REST API.
1. Qu’est-ce que TCP ?
TCP (Transmission Control Protocol) est un protocole de communication fiable et orienté connexion.
Les paquets de données sont envoyés dans l’ordre, et les paquets perdus ou corrompus sont retransmis.
TCP fonctionne selon un modèle client–serveur : une partie écoute (TcpListener), l’autre se connecte (TcpClient).
2. Un serveur simple avec TcpListener
L’exemple suivant montre un serveur TCP qui écoute les connexions entrantes sur le port 5000.
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
class TcpServer
{
public static async Task StartAsync()
{
var listener = new TcpListener(IPAddress.Loopback, 5000);
listener.Start();
Console.WriteLine("Serveur démarré. Écoute sur le port 5000...");
while (true)
{
using TcpClient client = await listener.AcceptTcpClientAsync();
Console.WriteLine("Nouveau client connecté !");
using var stream = client.GetStream();
using var reader = new StreamReader(stream, Encoding.UTF8);
using var writer = new StreamWriter(stream, Encoding.UTF8) { AutoFlush = true };
string? message = await reader.ReadLineAsync();
Console.WriteLine($"Message reçu : {message}");
await writer.WriteLineAsync($"Réponse du serveur : {message?.ToUpper()}");
}
}
static async Task Main() => await StartAsync();
}
À chaque nouvelle connexion, le serveur lit le message, le convertit en majuscules et le renvoie.
IPAddress.Loopback représente uniquement la machine locale.
3. Connexion d’un client avec TcpClient
Côté client, on peut utiliser TcpClient pour se connecter au serveur :
using System;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
class TcpClientApp
{
static async Task Main()
{
using var client = new TcpClient();
await client.ConnectAsync("127.0.0.1", 5000);
using var stream = client.GetStream();
using var writer = new StreamWriter(stream, Encoding.UTF8) { AutoFlush = true };
using var reader = new StreamReader(stream, Encoding.UTF8);
Console.Write("Message : ");
string message = Console.ReadLine()!;
await writer.WriteLineAsync(message);
string response = await reader.ReadLineAsync() ?? "";
Console.WriteLine($"Réponse du serveur : {response}");
}
}
Après avoir lancé le serveur, exécutez ce client. Le message envoyé sera renvoyé en majuscules.
4. Appels Web et REST API avec HttpClient
Aujourd’hui, la forme la plus courante de communication réseau repose sur les services REST basés sur HTTP.
En .NET, la classe HttpClient est utilisée à cette fin.
Elle fonctionne de manière asynchrone, est réutilisable et idéale pour les échanges de données JSON.
using System;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
class HttpClientExample
{
static readonly HttpClient http = new HttpClient();
static async Task Main()
{
var url = "https://jsonplaceholder.typicode.com/posts/1";
Console.WriteLine($"GET {url}");
var response = await http.GetAsync(url);
string json = await response.Content.ReadAsStringAsync();
var post = JsonSerializer.Deserialize<Post>(json);
Console.WriteLine($"Titre : {post?.Title}");
}
public class Post
{
public int Id { get; set; }
public string? Title { get; set; }
public string? Body { get; set; }
}
}
Cet exemple récupère des données JSON depuis une API REST et les désérialise dans une classe C# (Post).
JsonSerializer est la bibliothèque JSON intégrée de .NET.
5. Envoi d’une requête POST
Avec HttpClient, vous pouvez envoyer une requête POST en créant manuellement le contenu JSON ou en utilisant la sérialisation.
using System.Net.Http;
using System.Text;
using System.Text.Json;
var http = new HttpClient();
var newPost = new
{
title = "Nouvel article",
body = "Bonjour le monde !",
userId = 1
};
var json = JsonSerializer.Serialize(newPost);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await http.PostAsync("https://jsonplaceholder.typicode.com/posts", content);
Console.WriteLine($"Statut : {response.StatusCode}");
string result = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Réponse : {result}");
Cet exemple illustre la méthode de base pour envoyer des données à une API REST. Dans les applications réelles, il est important d’utiliser le modèle async/await pour de meilleures performances.
6. Cycle de vie de HttpClient (Meilleures pratiques)
Créer un nouvel objet HttpClient pour chaque requête entraîne une surconsommation de ressources. La bonne approche consiste à utiliser une seule instance (singleton) :
// Program.cs
builder.Services.AddHttpClient<IMyApiService, MyApiService>();
// Service
public class MyApiService : IMyApiService
{
private readonly HttpClient _http;
public MyApiService(HttpClient http)
{
_http = http;
_http.BaseAddress = new Uri("https://api.example.com/");
}
public async Task<User?> GetUserAsync(int id)
{
return await _http.GetFromJsonAsync<User>($"users/{id}");
}
}
Dans ASP.NET Core, la HttpClientFactory gère automatiquement le pool de connexions.
7. Gestion des erreurs et délais d’attente (Timeout)
Lors des appels HTTP, il est important de gérer les délais, les erreurs et les exceptions inattendues.
var http = new HttpClient { Timeout = TimeSpan.FromSeconds(5) };
try
{
var response = await http.GetAsync("https://api.github.com/repos/dotnet/runtime");
response.EnsureSuccessStatusCode(); // Lève une exception pour les statuts ≠ 200–299
string content = await response.Content.ReadAsStringAsync();
Console.WriteLine("Requête réussie : " + content.Length + " octets");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Erreur HTTP : {ex.Message}");
}
catch (TaskCanceledException)
{
Console.WriteLine("Délai dépassé !");
}
8. SSL, en-têtes et utilisation de tokens
La plupart des API modernes utilisent l’en-tête Authorization pour l’authentification.
Vous pouvez facilement ajouter des en-têtes personnalisés et des paramètres spécifiques :
var http = new HttpClient();
http.DefaultRequestHeaders.Add("Authorization", "Bearer <token>");
http.DefaultRequestHeaders.Add("User-Agent", "MyApp/1.0");
var res = await http.GetAsync("https://api.github.com/user");
Console.WriteLine(res.StatusCode);
Les connexions HTTPS sont sécurisées par défaut. En environnement de développement (par ex. certificats auto-signés), vous pouvez configurer un gestionnaire personnalisé.
9. Flux asynchrones pour les grandes données
Pour les fichiers volumineux ou les flux de données, il est possible de lire directement à partir du Stream sans tout charger en mémoire :
using var http = new HttpClient();
using var response = await http.GetAsync("https://example.com/bigfile.zip", HttpCompletionOption.ResponseHeadersRead);
await using var stream = await response.Content.ReadAsStreamAsync();
using var file = File.Create("telecharge.zip");
await stream.CopyToAsync(file);
Console.WriteLine("Fichier téléchargé.");
Cette méthode utilise la mémoire de façon efficace ; le fichier n’est jamais entièrement chargé en RAM.
10. Exemple : Consommer une API REST (WeatherService)
L’exemple ci-dessous récupère des données à partir d’une API météo et les convertit en modèle.
public class WeatherInfo
{
public string? City { get; set; }
public float Temperature { get; set; }
public string? Condition { get; set; }
}
public class WeatherService
{
private readonly HttpClient _http;
public WeatherService(HttpClient http)
{
_http = http;
_http.BaseAddress = new Uri("https://api.weatherapi.com/v1/");
}
public async Task<WeatherInfo?> GetAsync(string city)
{
var key = "<your-api-key>";
string url = $"current.json?key={key}&q={city}&aqi=no";
var res = await _http.GetAsync(url);
res.EnsureSuccessStatusCode();
using var s = await res.Content.ReadAsStreamAsync();
using var doc = await JsonDocument.ParseAsync(s);
return new WeatherInfo
{
City = city,
Temperature = doc.RootElement.GetProperty("current").GetProperty("temp_c").GetSingle(),
Condition = doc.RootElement.GetProperty("current").GetProperty("condition").GetProperty("text").GetString()
};
}
}
Cette structure respecte les principes de la Clean Architecture et utilise Dependency Injection via HttpClientFactory.
11. Performances et bonnes pratiques
- Réutilisez HttpClient (instance unique ou
IHttpClientFactory). - Gérez les délais et les politiques de reprise avec la bibliothèque Polly.
- Utilisez
ConfigureAwait(false)dans les appels asynchrones pour éviter les blocages (deadlocks). - Si vous utilisez TcpClient, libérez correctement les ressources avec
usingetawait. - Ajoutez toujours une gestion des exceptions et des logs pour les opérations réseau (I/O).
Résumé (TL;DR)
- TcpClient/TcpListener : Fournissent une communication TCP bas niveau basée sur la connexion.
- HttpClient : Client haut niveau pour communiquer avec des APIs REST.
- GetAsync, PostAsync : Envoient des requêtes HTTP ; la conversion JSON s’effectue avec
JsonSerializer. - HttpClientFactory : Recommandé pour la gestion des instances et les performances.
- Opérations asynchrones : Utilisez
await, gérez lesTimeoutet les erreurs de façon appropriée.
Articles connexes
Astuces Visual Studio / VS Code pour C#
Découvrez des astuces Visual Studio et VS Code pour C# afin d’améliorer la productivité et les flux de travail.
Bases de la programmation asynchrone en C# (async/await)
Apprenez async et await en C# pour créer des applications réactives avec des tâches asynchrones et des exemples pratiques.
Méthodes et utilisation des paramètres en C#
Apprenez à définir des méthodes et à utiliser des paramètres en C#, y compris les paramètres par valeur et par référence avec exemples.