Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
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!"));
HttpWebRequest vers HttpClient, SocketsHttpHandler guide de migration
Migrer l’utilisation ServicePointManager
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é comme ConnectionLimit ou Expect100Continue, elle a un impact sur chaque nouvelle ServicePoint instance.
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 | Remarques |
|---|---|---|
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 | Remarques |
|---|---|---|
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 | Remarques |
|---|---|---|
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. La compréhension de 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 HttpRequestMessage propriétés
Voici un exemple d'utilisation de HttpClient et HttpRequestMessage ensemble :
var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, "https://example.com"); // Method and RequestUri usage
using 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;
Usage 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 la rotation DNS en gérant manuellement la résolution DNS et en alternant entre les adresses IP à l’aide de la propriété ConnectCallback de SocketsHttpHandler.
Pour activer le tourniquet DNS avec HttpClient, vous pouvez utiliser la propriété ConnectCallback pour résoudre manuellement les entrées DNS et faire rotater 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 à l’aide de 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
Pour l’implémentation de DnsRoundRobinConnector, consultez DnsRoundRobin.cs.
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 des SocketsHttpHandler propriétés
SocketsHttpHandler est un gestionnaire puissant et flexible dans .NET qui fournit des options de configuration avancées pour la gestion des connexions HTTP. En définissant différentes propriétés de SocketsHttpHandler, vous pouvez ajuster le comportement de votre client HTTP pour répondre à des exigences spécifiques, telles que l’optimisation des performances, les améliorations de sécurité et la gestion des connexions personnalisées.
Voici un exemple de configuration SocketsHttpHandler avec différentes propriétés et de l’utiliser 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 liées au certificat et au protocole 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érifier la liste de révocation de 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 à l’aide de 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 à l’aide de 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.
- Configurez
HttpClientHandlerouSocketsHttpHandlerpour 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 à l'aide de la propriété DefaultRequestHeaders de HttpClient ou de la propriété Headers de HttpRequestMessage.
Exemple : Définir des en-têtes de requête personnalisés
Définition des en-têtes de requête personnalisés par défaut dans HttpClient
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Custom-Header", "value");
Définition d’en-têtes de requête personnalisés dans HttpRequestMessage
using 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éfinition des en-têtes de requête par défaut courants dans HttpClient
using System.Net.Http.Headers;
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "token");
Définition d’en-têtes de requête courants dans HttpRequestMessage
using System.Net.Http.Headers;
using 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();
using 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 MaximumErrorResponseLength 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
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. Définir simplement les en-têtes ne suffit pas pour obtenir la mise 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 à l’aide de HttpClient:
public static class CachePolicy
{
public static void AddCacheControlHeaders(HttpRequestMessage request, RequestCachePolicy policy)
Pour l’implémentation de AddCacheControlHeaders, consultez AddCacheControlHeaders.cs.
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 vers HttpWebRequestHttpClient, il est important de comprendre les différences dans la façon dont ces deux API gèrent la mise en mémoire tampon.
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 à l’aide de 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ête lui-même, mais délègue cette responsabilité au HttpContent utilisé. Le contenu comme StringContent ou ByteArrayContent sont déjà mis en mémoire tampon logiquement, tandis que l’utilisation StreamContent n’entraîne 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();
using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri);
request.Content = new StreamContent(yourStream);
await request.Content.LoadIntoBufferAsync();
using 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);