Définissez KeepAlive sur false lorsque vous interagissez avec des hôtes externes dans un plug-in
Catégorie : Performance
Potentiel d’impact : Élevé
Symptômes
Si un plug-in fait des demandes web externes et essaie d’utiliser KeepAlive
dans une connexion fermée, le plug-in échouera à exécuter la demande Web. Si le plug-in est enregistré :
de manière synchrone, les utilisateurs peuvent rencontrer :
- Des applications basées sur des modèles qui ne répondent pas
- Des interactions lentes avec le client
- L’arrêt des réponses du navigateur
de manière asynchrone, les exécutions de plug-in peuvent prendre un certain temps avant d’échouer.
Recommandation
- Dans HTTP 1.1, toutes les connexions sont considérées persistantes (
KeepAlive
est True) sauf instruction contraire. En raison du fait que les plug-ins sont exécutés en isolation, le service Sandbox les convertit en exécutions de courte durée dont généralementKeepAlive
ne tirerait pas profit. Pour éviter tout problème de connexion aux services externes nous vous conseillons de désactiverKeepAlive
dans les plug-ins. Si votre service externe spécifique tirerait profit d’utiliser des sessions persistantes pour des raisons de performances, envoyez activement unKeepAlive
à un intervalle de moitié du délai d’inactivité (30 secondes) pour empêcher la fermeture de la connexion.
Les exemples suivants expliquent comment définir explicitement KeepAlive
sur Faux selon la méthode à utiliser pour établir une connexion à un service externe :
HttpWebRequest
HttpWebRequest req = WebRequest.Create("https://www.contoso.com/api/stuff") as HttpWebRequest; if (req != null) { req.KeepAlive = false; HttpWebResponse response = (HttpWebResponse)req.GetResponse(); }
WebClient
private string RequestString(Uri location) { using (var client = new MyWebClient()) { return client.DownloadString(location); } } internal class MyWebClient : WebClient { // Overrides the GetWebRequest method and sets keep alive to false protected override WebRequest GetWebRequest(Uri address) { HttpWebRequest req = (HttpWebRequest)base.GetWebRequest(address); req.KeepAlive = false; return req; } }
Instance de
WCF ClientBase< T >
OrganizationServiceClient client = null; try { var address = new EndpointAddress("https://www.contoso.com/Custom.svc"); var transport = new HttpsTransportBindingElement(); transport.KeepAliveEnabled = false; var binding = new CustomBinding(transport); client = new OrganizationServiceClient(binding, address); WhoAmIResponse response = client.Execute(new WhoAmIRequest()) as WhoAmIResponse; } catch (Exception ex) { client.Abort(); } finally { client.Close(); }
Méthode statique
WCF ChannelFactory< TChannel >
IRequestChannel channel = null; try { var address = new EndpointAddress("https://www.contoso.com/Custom.svc"); var transport = new HttpsTransportBindingElement(); transport.KeepAliveEnabled = false; var binding = new CustomBinding(transport); channel = ChannelFactory<IRequestChannel>.CreateChannel(binding, address); Message request = Message.CreateMessage(MessageVersion.Soap12, "some action", "message body"); Message response = channel.Request(request); } catch (Exception ex) { channel.Abort(); } finally { channel.Close(); }
Instance de
WCF ChannelFactory< TChannel >
ChannelFactory<IRequestChannel> factory = null; IRequestChannel channel = null; try { var address = new EndpointAddress("https://www.contoso.com/Custom.svc"); var transport = new HttpsTransportBindingElement(); transport.KeepAliveEnabled = false; var binding = new CustomBinding(transport); factory = new ChannelFactory<IRequestChannel>(binding, address); channel = factory.CreateChannel(); Message request = Message.CreateMessage(MessageVersion.Soap12, "some action", "message body"); Message response = channel.Request(request); } catch (Exception ex) { channel.Abort(); factory.Abort(); } finally { channel.Close(); factory.Close(); }
Schémas problématiques
Afin de remplacer la valeur par défaut de KeepAlive
par des interactions non-WCF, l’approche à adopter pour tirer profit de HttpWebRequest pour effectuer les interactions avec le serveur Web, mais définissez d’abord la propriété KeepAlive
sur false.
Les exemples suivants expliquent le schéma problématique selon la méthode à utiliser pour établir une connexion à un service externe :
Avertissement
Ces schémas doivent être évités.
HttpWebRequest
WebRequest request = WebRequest.Create("https://www.contoso.com/api/stuff"); //KeepAlive not explicitly defined as true. However, default behavior is KeepAlive = true. HttpWebResponse response = (HttpWebResponse)request.GetResponse(); response.Close();
WebClient
using (var client = new WebClient()) { string url = "https://www.contoso.com/api/stuff"; //KeepAlive not explicitly defined as true. However, default behavior is KeepAlive = true. string result = client.DownloadString(url); }
Instance de
WCF ClientBase< T >
OrganizationServiceClient client = null; try { var address = new EndpointAddress("https://www.contoso.com/Custom.svc"); var binding = new BasicHttpsBinding(); //KeepAlive not explicitly defined as true. However, default behavior is KeepAlive = true. client = new OrganizationServiceClient(binding, address); WhoAmIResponse response = client.Execute(new WhoAmIRequest()) as WhoAmIResponse; } catch (Exception ex) { client.Abort(); } finally { client.Close(); }
Méthode statique
WCF ChannelFactory< TChannel >
IRequestChannel channel = null; try { var address = new EndpointAddress("https://www.contoso.com/Custom.svc"); var binding = new BasicHttpsBinding(); //KeepAlive not explicitly defined as true. However, default behavior is KeepAlive = true. channel = ChannelFactory<IRequestChannel>.CreateChannel(binding, address); Message request = Message.CreateMessage(MessageVersion.Soap12, "some action", "message body"); Message response = channel.Request(request); } catch (Exception ex) { channel.Abort(); } finally { channel.Close(); }
Instance de
WCF ChannelFactory< TChannel >
ChannelFactory<IRequestChannel> factory = null; IRequestChannel channel = null; try { var address = new EndpointAddress("https://www.contoso.com/Custom.svc"); var binding = new BasicHttpsBinding(); //KeepAlive not explicitly defined as true. However, default behavior is KeepAlive = true. factory = new ChannelFactory<IRequestChannel>(binding, address); channel = factory.CreateChannel(); Message request = Message.CreateMessage(MessageVersion.Soap12, "some action", "message body"); Message response = channel.Request(request); } catch (Exception ex) { channel.Abort(); factory.Abort(); } finally { channel.Close(); factory.Close(); }
Informations supplémentaires
Les plug-ins interagissant avec des services externes peuvent rencontrer des délai d’exécution anormaux. Le problème provient de la (propriété KeepAlive) des requêtes HTTP publiées sur les serveurs Web externes. Si la propriété KeepAlive
est définie sur True ou non définie du tout (le comportement par défaut est True) le client Sandbox sur le serveur peut continuer à essayer d’utiliser une session persistante même si la session a expiré suite à la configuration périphérique du réseau. La cause du délai d’exécution étendu est dû au réseau réessayant la demande jusqu’à ce que la connexion soit finalement réinitialisée.
Important
Cela affecte tout le code qui initie les requêtes HTTP à un serveur Web à l’aide de System.Net.WebClient, de System.Net.WebRequest ou de System.Net.HttpWebRequest ainsi que les communications client Windows Communication Foundation (WCF) à l’aide d’un transport HTTP liant directement ou indirectement via ChannelFactory<TChannel> ou ClientBase<T>.
Ce comportement est transparent aux utilisateurs finaux et la journalisation standard comme l’exécution provient des délais réseau. Si le plug-in a été enregistré en tant qu’événement synchrone, les utilisateurs peuvent rencontrer des problèmes de performances intermittents pendant ces opérations enregistrées ce qui peut entraîner l’absence de réponse des applications basées sur des modèles. Si le plug-in est enregistré de manière asynchrone, le problème est observé uniquement en examinant les délais d’exécution du plug-in et en constatant que l’exécution prend plus de temps que la normale ou que prévu.
Voir aussi
Exemple : Accès Web d’un plug-in placé dans le bac à sable
Équilibrage de la charge (WCF)
Propriété HttpTransportBindingElement.KeepAliveEnabled
Propriété HttpWebRequest.KeepAlive
Notes
Pouvez-vous nous indiquer vos préférences de langue pour la documentation ? Répondez à un court questionnaire. (veuillez noter que ce questionnaire est en anglais)
Le questionnaire vous prendra environ sept minutes. Aucune donnée personnelle n’est collectée (déclaration de confidentialité).