Partager via


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

  1. 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éralement KeepAlive ne tirerait pas profit. Pour éviter tout problème de connexion aux services externes nous vous conseillons de désactiver KeepAlive dans les plug-ins. Si votre service externe spécifique tirerait profit d’utiliser des sessions persistantes pour des raisons de performances, envoyez activement un KeepAlive à 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é).