Guide de migration de HttpWebRequest vers HttpClient
Cet article vise à guider les développeurs dans le processus de migration de HttpWebRequest, ServicePoint et ServicePointManager vers HttpClient. La migration est nécessaire en raison de l’obsolescence des anciennes API et des nombreux avantages offerts par HttpClient, notamment une amélioration des performances, une meilleure gestion des ressources et une conception d’API plus moderne et flexible. En suivant les étapes décrites dans ce document, les développeurs pourront faire la transition de leurs bases de code en douceur et tirer pleinement parti des fonctionnalités fournies par HttpClient.
Avertissement
La migration de HttpWebRequest
, ServicePoint
et ServicePointManager
vers HttpClient
n’est pas seulement une amélioration de performances « souhaitable ». Il est essentiel de comprendre que les performances de la logique WebRequest
existante risquent de se dégrader considérablement lorsque vous passerez à .NET (Core). En effet, WebRequest
est maintenu comme une couche de compatibilité minimale, ce qui signifie qu'il manque de nombreuses optimisations, telles que la réutilisation des connexions dans de nombreux cas. Par conséquent, passer à HttpClient
est essentiel pour garantir que les performances de votre application et la gestion des ressources soient conformes aux normes modernes.
Migrer de HttpWebRequest vers HttpClient
Commençons par quelques exemples :
Simple requête GET utilisant HttpWebRequest
Voici un exemple de ce à quoi le code pourrait ressembler :
HttpWebRequest request = WebRequest.CreateHttp(uri);
using WebResponse response = await request.GetResponseAsync();
Simple requête GET utilisant HttpClient
Voici un exemple de ce à quoi le code pourrait ressembler :
HttpClient client = new();
using HttpResponseMessage message = await client.GetAsync(uri);
Simple requête POST utilisant HttpWebRequest
Voici un exemple de ce à quoi le code pourrait ressembler :
HttpWebRequest request = WebRequest.CreateHttp(uri);
request.Method = "POST";
request.ContentType = "text/plain";
await using Stream stream = await request.GetRequestStreamAsync();
await stream.WriteAsync("Hello World!"u8.ToArray());
using WebResponse response = await request.GetResponseAsync();
Simple requête POST utilisant HttpClient
Voici un exemple de ce à quoi le code pourrait ressembler :
HttpClient client = new();
using HttpResponseMessage responseMessage = await client.PostAsync(uri, new StringContent("Hello World!"));
Guide de migration de HttpWebRequest vers HttpClient, SocketsHttpHandler
Migrer l'utilisation du ServicePoint(Manager)
Vous devez savoir que ServicePointManager
est une classe statique, ce qui signifie que toute modification apportée à ses propriétés aura un effet global sur tous les objets ServicePoint
nouvellement créés au sein de l'application. Par exemple, lorsque vous modifiez une propriété telle que ConnectionLimit
ou Expect100Continue
, cela a un impact sur chaque nouvelle instance de ServicePoint.
Avertissement
Dans .NET moderne, HttpClient
ne prend pas en compte les configurations définies sur ServicePointManager
.
ServicePointManager mappage des propriétés
Avertissement
Dans .NET moderne, les valeurs par défaut pour les propriétés UseNagleAlgorithm
et Expect100Continue
sont définies sur false
. Ces valeurs étaient true
par défaut dans .NET Framework.
ServicePointManager mappage des méthodes
ServicePointManager Ancien API | Nouvelle API | Notes |
---|---|---|
FindServicePoint |
Pas d’API équivalente | Aucune solution de contournement |
SetTcpKeepAlive |
Pas d’API équivalente directe | Utilisation de SocketsHttpHandler et ConnectCallback. |
ServicePoint mappage des propriétés
ServicePoint Ancien API | Nouvelle API | Notes |
---|---|---|
Address |
HttpRequestMessage.RequestUri |
Il s’agit de l’URI de la requête, cette information se trouve sous HttpRequestMessage . |
BindIPEndPointDelegate |
Pas d’API équivalente directe | Utilisation de SocketsHttpHandler et ConnectCallback. |
Certificate |
Pas d’API équivalente directe | Cette information peut être récupérée depuis RemoteCertificateValidationCallback . Exemple : Récupérer un certificat. |
ClientCertificate |
Pas d’API équivalente | Exemple : Activation de l'authentification mutuelle. |
ConnectionLeaseTimeout |
SocketsHttpHandler.PooledConnectionLifetime |
Réglage équivalent dans HttpClient. |
ConnectionLimit |
MaxConnectionsPerServer | Exemple : Définition des propriétés de SocketsHttpHandler. |
ConnectionName |
Pas d’API équivalente | Aucune solution de contournement |
CurrentConnections |
Pas d’API équivalente | Voir Télémétrie réseau en .NET. |
Expect100Continue |
ExpectContinue | Exemple : Définir les en-têtes de la requête. |
IdleSince |
Pas d’API équivalente | Aucune solution de contournement |
MaxIdleTime |
PooledConnectionIdleTimeout | Exemple : Définition des propriétés de SocketsHttpHandler. |
ProtocolVersion |
HttpRequestMessage.Version |
Exemple : utilisation des propriétés de HttpRequestMessage : Utilisation des propriétés HttpRequestMessage. |
ReceiveBufferSize |
Pas d’API équivalente directe | Utilisation de SocketsHttpHandler et ConnectCallback. |
SupportsPipelining |
Pas d’API équivalente | HttpClient ne supporte pas le pipelining. |
UseNagleAlgorithm |
Pas d’API équivalente directe | Utilisation de SocketsHttpHandler et ConnectCallback. |
ServicePoint mappage des méthodes
ServicePoint Ancien API | Nouvelle API | Notes |
---|---|---|
CloseConnectionGroup |
Pas d'équivalent | Aucune solution de contournement |
SetTcpKeepAlive |
Pas d’API équivalente directe | Utilisation de SocketsHttpHandler et ConnectCallback. |
Utilisation des propriétés HttpClient et HttpRequestMessage
Lorsque vous travaillez avec HttpClient dans .NET, vous avez accès à diverses propriétés qui vous permettent de configurer et de personnaliser les requêtes et réponses HTTP. Comprendre ces propriétés peut vous aider à tirer le meilleur parti de HttpClient et à garantir que votre application communique efficacement et en toute sécurité avec les services web.
Exemple : Utilisation des propriétés HttpRequestMessage
Voici un exemple d’utilisation combinée de HttpClient et HttpRequestMessage :
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://example.com"); // Method and RequestUri usage
var request = new HttpRequestMessage() // Alternative way to set RequestUri and Method
{
RequestUri = new Uri("https://example.com"),
Method = HttpMethod.Post
};
request.Headers.Add("Custom-Header", "value");
request.Content = new StringContent("somestring");
using var response = await client.SendAsync(request);
var protocolVersion = response.RequestMessage.Version; // Fetch `ProtocolVersion`.
Exemple : Récupérer l'URI redirigé
Voici un exemple de récupération de l’URI redirigé (identique à HttpWebRequest.Address
) :
var client = new HttpClient();
using var response = await client.GetAsync(uri);
var redirectedUri = response.RequestMessage.RequestUri;
Utilisation de SocketsHttpHandler et ConnectCallback
La propriété ConnectCallback
dans SocketsHttpHandler
permet aux développeurs de personnaliser le processus d’établissement d’une connexion TCP. Cela peut être utile dans les scénarios où vous devez contrôler la résolution DNS ou appliquer des options spécifiques aux sockets lors de la connexion. En utilisant ConnectCallback
, vous pouvez intercepter et modifier le processus de connexion avant qu’il ne soit utilisé par HttpClient
.
Exemple : Lier l'adresse IP à la socket
Dans l’approche ancienne utilisant HttpWebRequest
, vous pourriez avoir utilisé une logique personnalisée pour lier une adresse IP spécifique à un socket. Voici comment vous pouvez obtenir une fonctionnalité similaire en utilisant HttpClient
et ConnectCallback
:
Ancien code utilisant HttpWebRequest
:
HttpWebRequest request = WebRequest.CreateHttp(uri);
request.ServicePoint.BindIPEndPointDelegate = (servicePoint, remoteEndPoint, retryCount) =>
{
// Bind to a specific IP address
IPAddress localAddress = IPAddress.Parse("192.168.1.100");
return new IPEndPoint(localAddress, 0);
};
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Nouveau code utilisant HttpClient
et ConnectCallback
:
var handler = new SocketsHttpHandler
{
ConnectCallback = async (context, cancellationToken) =>
{
// Bind to a specific IP address
IPAddress localAddress = IPAddress.Parse("192.168.1.100");
var socket = new Socket(localAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
socket.Bind(new IPEndPoint(localAddress, 0));
await socket.ConnectAsync(context.DnsEndPoint, cancellationToken);
return new NetworkStream(socket, ownsSocket: true);
}
catch
{
socket.Dispose();
throw;
}
}
};
var client = new HttpClient(handler);
using var response = await client.GetAsync(uri);
Exemple : lier l'adresse IP à la socket Appliquer des options de socket spécifiques
Si vous devez appliquer des options spécifiques aux sockets, comme l’activation du keep-alive TCP, vous pouvez utiliser ConnectCallback
pour configurer le socket avant qu’il ne soit utilisé par HttpClient
. En fait, ConnectCallback
est plus flexible pour configurer les options des sockets.
Ancien code utilisant HttpWebRequest
:
ServicePointManager.ReusePort = true;
HttpWebRequest request = WebRequest.CreateHttp(uri);
request.ServicePoint.SetTcpKeepAlive(true, 60000, 1000);
request.ServicePoint.ReceiveBufferSize = 8192;
request.ServicePoint.UseNagleAlgorithm = false;
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Nouveau code utilisant HttpClient
et ConnectCallback
:
var handler = new SocketsHttpHandler
{
ConnectCallback = async (context, cancellationToken) =>
{
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
try
{
// Setting TCP Keep Alive
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, 60);
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, 1);
// Setting ReceiveBufferSize
socket.ReceiveBufferSize = 8192;
// Enabling ReusePort
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseUnicastPort, true);
// Disabling Nagle Algorithm
socket.NoDelay = true;
await socket.ConnectAsync(context.DnsEndPoint, cancellationToken);
return new NetworkStream(socket, ownsSocket: true);
}
catch
{
socket.Dispose();
throw;
}
}
};
var client = new HttpClient(handler);
using var response = await client.GetAsync(uri);
Exemple : Activer le DNS round robin
Le DNS Round Robin est une technique utilisée pour répartir le trafic réseau entre plusieurs serveurs en faisant tourner une liste d’adresses IP associées à un même nom de domaine. Cela aide à équilibrer la charge et à améliorer la disponibilité des services. Lorsque vous utilisez HttpClient, vous pouvez implémenter le DNS Round Robin en gérant manuellement la résolution DNS et en faisant tourner les adresses IP à l’aide de la propriété ConnectCallback de SocketsHttpHandler.
Pour activer le DNS Round Robin avec HttpClient, vous pouvez utiliser la propriété ConnectCallback pour résoudre manuellement les entrées DNS et faire tourner les adresses IP. Voici un exemple pour HttpWebRequest
et HttpClient
:
Ancien code utilisant HttpWebRequest
:
ServicePointManager.DnsRefreshTimeout = 60000;
ServicePointManager.EnableDnsRoundRobin = true;
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Dans l’ancienne API HttpWebRequest
, l’activation du DNS Round Robin était simple grâce à la prise en charge intégrée de cette fonctionnalité. Cependant, la nouvelle API HttpClient
ne fournit pas la même fonctionnalité intégrée. Néanmoins, vous pouvez obtenir un comportement similaire en implémentant un DnsRoundRobinConnector
qui fait tourner manuellement les adresses IP retournées par la résolution DNS.
Nouveau code utilisant HttpClient
:
// This is available as NuGet Package: https://www.nuget.org/packages/DnsRoundRobin/
// The original source code can be found also here: https://github.com/MihaZupan/DnsRoundRobin
public sealed class DnsRoundRobinConnector : IDisposable
Vous pouvez trouver l’implémentation de DnsRoundRobinConnector
ici.
DnsRoundRobinConnector
Utilisation :
private static readonly DnsRoundRobinConnector s_roundRobinConnector = new(
dnsRefreshInterval: TimeSpan.FromSeconds(10),
endpointConnectTimeout: TimeSpan.FromSeconds(5));
static async Task DnsRoundRobinConnectAsync()
{
var handler = new SocketsHttpHandler
{
ConnectCallback = async (context, cancellation) =>
{
Socket socket = await DnsRoundRobinConnector.Shared.ConnectAsync(context.DnsEndPoint, cancellation);
// Or you can create and use your custom DnsRoundRobinConnector instance
// Socket socket = await s_roundRobinConnector.ConnectAsync(context.DnsEndPoint, cancellation);
return new NetworkStream(socket, ownsSocket: true);
}
};
var client = new HttpClient(handler);
HttpResponseMessage response = await client.GetAsync(Uri);
}
Exemple : Définir les propriétés de SocketsHttpHandler
SocketsHttpHandler est un gestionnaire puissant et flexible dans .NET qui offre des options de configuration avancées pour la gestion des connexions HTTP. En définissant diverses propriétés de SocketsHttpHandler, vous pouvez affiner le comportement de votre client HTTP pour répondre à des exigences spécifiques, telles que l’optimisation des performances, les améliorations de la sécurité et la gestion personnalisée des connexions.
Voici un exemple de configuration de SocketsHttpHandler avec diverses propriétés et de son utilisation avec HttpClient :
var cookieContainer = new CookieContainer();
cookieContainer.Add(new Cookie("cookieName", "cookieValue"));
var handler = new SocketsHttpHandler
{
AllowAutoRedirect = true,
AutomaticDecompression = DecompressionMethods.All,
Expect100ContinueTimeout = TimeSpan.FromSeconds(1),
CookieContainer = cookieContainer,
Credentials = new NetworkCredential("user", "pass"),
MaxAutomaticRedirections = 10,
MaxResponseHeadersLength = 1,
Proxy = new WebProxy("http://proxyserver:8080"), // Don't forget to set UseProxy
UseProxy = true,
};
var client = new HttpClient(handler);
using var response = await client.GetAsync(uri);
Exemple : Changer ImpersonationLevel
Cette fonctionnalité est spécifique à certaines plateformes et est quelque peu obsolète. Si vous avez besoin d’une solution de contournement, vous pouvez vous référer à cette section du code.
Utilisation des propriétés relatives aux certificats et à TLS dans HttpClient
Lorsque vous travaillez avec HttpClient
, vous pourriez avoir besoin de gérer des certificats clients pour diverses raisons, telles que la validation personnalisée des certificats serveur ou la récupération du certificat serveur. HttpClient
fournit plusieurs propriétés et options pour gérer efficacement les certificats.
Exemple : Vérification de la liste de révocation des certificats avec SocketsHttpHandler
La propriété CheckCertificateRevocationList
dans SocketsHttpHandler.SslOptions
permet aux développeurs d’activer ou de désactiver la vérification des listes de révocation de certificats (CRL) lors de la poignée de main SSL/TLS. L’activation de cette propriété garantit que le client vérifie si le certificat du serveur a été révoqué, renforçant ainsi la sécurité de la connexion.
Ancien code utilisant HttpWebRequest
:
ServicePointManager.CheckCertificateRevocationList = true;
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Nouveau code utilisant HttpClient
:
bool checkCertificateRevocationList = true;
var handler = new SocketsHttpHandler
{
SslOptions =
{
CertificateRevocationCheckMode = checkCertificateRevocationList ? X509RevocationMode.Online : X509RevocationMode.NoCheck,
}
};
var client = new HttpClient(handler);
using var response = await client.GetAsync(uri);
Exemple : Récupérer un certificat
Pour récupérer le certificat à partir de RemoteCertificateValidationCallback
dans HttpClient
, vous pouvez utiliser la propriété ServerCertificateCustomValidationCallback
de HttpClientHandler
ou SocketsHttpHandler.SslOptions
. Ce callback vous permet d’inspecter le certificat du serveur pendant la poignée de main SSL/TLS.
Ancien code utilisant HttpWebRequest
:
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
X509Certificate? serverCertificate = request.ServicePoint.Certificate;
Nouveau code utilisant HttpClient
:
X509Certificate? serverCertificate = null;
var handler = new SocketsHttpHandler
{
SslOptions = new SslClientAuthenticationOptions
{
RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
{
serverCertificate = certificate;
// Leave the validation as-is.
return sslPolicyErrors == SslPolicyErrors.None;
}
}
};
var client = new HttpClient(handler);
using var response = await client.GetAsync("https://example.com");
Exemple : Activer l'authentification mutuelle
L’authentification mutuelle, également connue sous le nom de SSL à deux voies ou d’authentification par certificat client, est un processus de sécurité dans lequel le client et le serveur s’authentifient mutuellement. Cela garantit que les deux parties sont bien celles qu’elles prétendent être, offrant une couche supplémentaire de sécurité pour les communications sensibles. Dans HttpClient
, vous pouvez activer l’authentification mutuelle en configurant HttpClientHandler
ou SocketsHttpHandler
pour inclure le certificat client et valider le certificat du serveur.
Pour activer l’authentification mutuelle, suivez ces étapes :
- Charger le certificat client.
- Configurer HttpClientHandler ou SocketsHttpHandler pour inclure le certificat client.
- Configurer le callback de validation du certificat serveur si une validation personnalisée est nécessaire.
Voici un exemple utilisant SocketsHttpHandler :
var handler = new SocketsHttpHandler
{
SslOptions = new SslClientAuthenticationOptions
{
ClientCertificates = new X509CertificateCollection
{
// Load the client certificate from a file
new X509Certificate2("path_to_certificate.pfx", "certificate_password")
},
RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
{
// Custom validation logic for the server certificate
return sslPolicyErrors == SslPolicyErrors.None;
}
}
};
var client = new HttpClient(handler);
using var response = await client.GetAsync(uri);
Utilisation des propriétés des en-têtes
Les en-têtes jouent un rôle crucial dans la communication HTTP, fournissant des métadonnées essentielles sur la requête et la réponse. Lorsque vous travaillez avec HttpClient
dans .NET, vous pouvez définir et gérer diverses propriétés d’en-têtes pour contrôler le comportement de vos requêtes et réponses HTTP. Comprendre comment utiliser efficacement ces propriétés d’en-têtes peut vous aider à garantir que votre application communique de manière efficace et sécurisée avec les services web.
Définition des en-têtes de requête
Les en-têtes de requête sont utilisés pour fournir des informations supplémentaires au serveur concernant la requête effectuée. Les cas d’utilisation courants incluent la spécification du type de contenu, la définition de jetons d’authentification et l’ajout d’en-têtes personnalisés. Vous pouvez définir des en-têtes de requête en utilisant la propriété DefaultRequestHeaders
de HttpClient
ou la propriété Headers de HttpRequestMessage
.
Exemple : Définir des en-têtes de requête personnalisés
Définir les en-têtes de requête personnalisés par défaut dans HttpClient
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Custom-Header", "value");
Définir les en-têtes de requête personnalisés dans HttpRequestMessage
var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Add("Custom-Header", "value");
Exemple : Définir des en-têtes de requête personnalisés Définir des en-têtes de requête communs
Lorsque vous travaillez avec HttpRequestMessage
dans .NET, la définition d’en-têtes de requête courants est essentielle pour fournir des informations supplémentaires au serveur concernant la requête effectuée. Ces en-têtes peuvent inclure des jetons d’authentification et bien plus encore. Configurer correctement ces en-têtes garantit que vos requêtes HTTP sont traitées correctement par le serveur.
Pour obtenir une liste complète des propriétés communes disponibles dans HttpRequestHeaders, consultez la section Propriétés.
Pour définir des en-têtes de requête courants dans HttpRequestMessage
, vous pouvez utiliser la propriété Headers
de l’objet HttpRequestMessage
. Cette propriété donne accès à la collection HttpRequestHeaders
, où vous pouvez ajouter ou modifier des en-têtes selon les besoins.
Définir les en-têtes de requête par défaut dans HttpClient
using System.Net.Http.Headers;
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "token");
Définir les en-têtes de requête courants dans HttpRequestMessage
using System.Net.Http.Headers;
var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "token");
Exemple : Définir des en-têtes de requête personnalisés Définir des en-têtes de contenu
Les en-têtes de contenu sont utilisés pour fournir des informations supplémentaires sur le corps d’une requête ou d’une réponse HTTP. Lorsque vous travaillez avec HttpClient
dans .NET, vous pouvez définir des en-têtes de contenu pour spécifier le type de média, l’encodage et d’autres métadonnées relatives au contenu envoyé ou reçu. Configurer correctement les en-têtes de contenu garantit que le serveur et le client peuvent interpréter et traiter correctement le contenu.
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, uri);
// Create the content and set the content headers
var jsonData = "{\"key\":\"value\"}";
var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
// The following headers are set automatically by `StringContent`. If you wish to override their values, you can do it like so:
// content.Headers.ContentType = new MediaTypeHeaderValue("application/json; charset=utf-8");
// content.Headers.ContentLength = Encoding.UTF8.GetByteCount(jsonData);
// Assign the content to the request
request.Content = content;
using var response = await client.SendAsync(request);
Exemple : Définir la longueur maximale de la réponse d’erreur dans HttpClient
L’utilisation de MaximumErrorResponseLength
permet aux développeurs de spécifier la longueur maximale du contenu de la réponse d’erreur que le gestionnaire va mettre en mémoire tampon. Cela est utile pour contrôler la quantité de données lues et stockées en mémoire lorsque le serveur renvoie une réponse d’erreur. En utilisant cette technique, vous pouvez éviter une utilisation excessive de la mémoire et améliorer les performances de votre application lors de la gestion de réponses d’erreur volumineuses.
Il existe plusieurs façons de le faire, nous examinerons la technique TruncatedReadStream
dans cet exemple :
internal sealed class TruncatedReadStream(Stream innerStream, long maxSize) : Stream
{
private long _maxRemainingLength = maxSize;
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => throw new NotSupportedException();
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
public override void Flush() => throw new NotSupportedException();
public override int Read(byte[] buffer, int offset, int count)
{
return Read(new Span<byte>(buffer, offset, count));
}
public override int Read(Span<byte> buffer)
{
int readBytes = innerStream.Read(buffer.Slice(0, (int)Math.Min(buffer.Length, _maxRemainingLength)));
_maxRemainingLength -= readBytes;
return readBytes;
}
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return ReadAsync(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
}
public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
int readBytes = await innerStream.ReadAsync(buffer.Slice(0, (int)Math.Min(buffer.Length, _maxRemainingLength)), cancellationToken)
.ConfigureAwait(false);
_maxRemainingLength -= readBytes;
return readBytes;
}
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
public override void SetLength(long value) => throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
public override ValueTask DisposeAsync() => innerStream.DisposeAsync();
protected override void Dispose(bool disposing)
{
if (disposing)
{
innerStream.Dispose();
}
}
}
Et l’exemple d’utilisation de TruncatedReadStream
:
int maxErrorResponseLength = 1 * 1024; // 1 KB
HttpClient client = new HttpClient();
using HttpResponseMessage response = await client.GetAsync(Uri);
if (response.Content is not null)
{
Stream responseReadStream = await response.Content.ReadAsStreamAsync();
// If MaxErrorResponseLength is set and the response status code is an error code, then wrap the response stream in a TruncatedReadStream
if (maxErrorResponseLength >= 0 && !response.IsSuccessStatusCode)
{
responseReadStream = new TruncatedReadStream(responseReadStream, maxErrorResponseLength);
}
// Read the response stream
Memory<byte> buffer = new byte[1024];
int readValue = await responseReadStream.ReadAsync(buffer);
}
Exemple : Appliquer les en-têtes CachePolicy Appliquer les en-têtes CachePolicy
Avertissement
HttpClient
n'a pas de logique intégrée pour mettre en cache les réponses. Il n’existe pas de solution de contournement autre que d’implémenter tout le mécanisme de mise en cache par vous-même. Simplement définir les en-têtes ne permettra pas de mettre en cache.
Lors de la migration de HttpWebRequest
vers HttpClient
, il est important de gérer correctement les en-têtes liés au cache, tels que pragma
et cache-control
. Ces en-têtes contrôlent la manière dont les réponses sont mises en cache et récupérées, garantissant que votre application fonctionne comme prévu en termes de performances et de fraîcheur des données.
Dans HttpWebRequest
, vous pourriez avoir utilisé la propriété CachePolicy
pour définir ces en-têtes. Cependant, dans HttpClient
, vous devez définir manuellement ces en-têtes sur la requête.
Ancien code utilisant HttpWebRequest
:
HttpWebRequest request = WebRequest.CreateHttp(uri);
request.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Dans l’ancienne API HttpWebRequest
, l’application de CachePolicy
était simple grâce à sa prise en charge intégrée de cette fonctionnalité. Cependant, la nouvelle API HttpClient
ne fournit pas la même fonctionnalité intégrée. Néanmoins, vous pouvez obtenir un comportement similaire en implémentant un AddCacheControlHeaders
qui ajoute manuellement les en-têtes liés au cache.
Nouveau code utilisant HttpClient
:
public static class CachePolicy
{
public static void AddCacheControlHeaders(HttpRequestMessage request, RequestCachePolicy policy)
Vous pouvez trouver l’implémentation de AddCacheControlHeaders
ici.
AddCacheControlHeaders
Utilisation :
static async Task AddCacheControlHeaders()
{
HttpClient client = new HttpClient();
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, Uri);
CachePolicy.AddCacheControlHeaders(requestMessage, new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore));
HttpResponseMessage response = await client.SendAsync(requestMessage);
}
Utilisation des propriétés de mise en mémoire tampon.
Lors de la migration de HttpWebRequest vers HttpClient
, il est important de comprendre les différences dans la gestion de la mise en mémoire tampon entre ces deux API.
Ancien code utilisant HttpWebRequest
:
Dans HttpWebRequest
, vous avez un contrôle direct sur les propriétés de mise en mémoire tampon via les propriétés AllowWriteStreamBuffering
et AllowReadStreamBuffering
. Ces propriétés permettent d’activer ou de désactiver la mise en mémoire tampon des données envoyées au serveur ou reçues du serveur.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.AllowReadStreamBuffering = true; // Default is `false`.
request.AllowWriteStreamBuffering = false; // Default is `true`.
Nouveau code utilisant HttpClient
:
Dans HttpClient
, il n’existe pas d’équivalents directs aux propriétés AllowWriteStreamBuffering
et AllowReadStreamBuffering
.
HttpClient ne met pas en mémoire tampon les corps de requêtes de lui-même, mais délègue cette responsabilité au HttpContent
utilisé. Des contenus comme StringContent
ou ByteArrayContent
sont logiquement déjà mis en mémoire tampon dans la mémoire, tandis que l’utilisation de StreamContent
n’engendrera pas de mise en mémoire tampon par défaut. Pour forcer la mise en mémoire tampon du contenu, vous pouvez appeler HttpContent.LoadIntoBufferAsync
avant d’envoyer la requête. Voici un exemple :
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri);
request.Content = new StreamContent(yourStream);
await request.Content.LoadIntoBufferAsync();
HttpResponseMessage response = await client.SendAsync(request);
Dans HttpClient
, la mise en mémoire tampon en lecture est activée par défaut. Pour l’éviter, vous pouvez spécifier l’indicateur HttpCompletionOption.ResponseHeadersRead
ou utiliser l’assistant GetStreamAsync
.
HttpClient client = new HttpClient();
using HttpResponseMessage response = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead);
await using Stream responseStream = await response.Content.ReadAsStreamAsync();
// Or simply
await using Stream responseStream = await client.GetStreamAsync(uri);