web-dev-qa-db-fra.com

System.Net.WebException: l'opération a expiré

J'ai un gros problème: je dois envoyer 200 objets à la fois et éviter les délais d'attente.

while (true)
{

    NameValueCollection data = new NameValueCollection();
    data.Add("mode", nat);

    using (var client = new WebClient())
    {
        byte[] response = client.UploadValues(serverA, data);
        responseData = Encoding.ASCII.GetString(response);

        string[] split = Javab.Split(new[] { '!' },  StringSplitOptions.RemoveEmptyEntries);
        string command = split[0];
        string server = split[1];
        string requestCountStr = split[2];

        switch (command)
        {
            case "check":
                int requestCount = Convert.ToInt32(requestCountStr);

                for (int i = 0; i < requestCount; i++)
                {
                    Uri myUri = new Uri(server);
                    WebRequest request = WebRequest.Create(myUri);
                    request.Timeout = 200000;
                    WebResponse myWebResponse = request.GetResponse();
                }
                break;
        }
    }    
}

Cela produit l'erreur:

Unhandled Exception: System.Net.WebException: The operation has timed out  
at System.Net.HttpWebRequest.GetResponse()  
at vir_fu.Program.Main(String[] args)

La boucle requestCount fonctionne correctement en dehors de mon code de base, mais lorsque je l’ajoute à mon projet, cette erreur se produit. J'ai essayé de configurer request.Timeout = 200; mais cela n'a pas aidé.

26
zimzim

Fermez/supprimez votre objet WebResponse.

33
Joe Chung

Cela signifie ce que ça dit. L'opération a pris trop de temps pour se terminer.

BTW, regardez WebRequest.Timeout et vous verrez que vous avez défini votre délai d’expiration pour 1/5 seconde.

32
John Saunders

Je ne suis pas sûr de votre premier exemple de code dans lequel vous utilisez WebClient.UploadValues, ce n'est pas vraiment suffisant pour continuer, pourriez-vous coller davantage de votre code environnant? En ce qui concerne votre code WebRequest, deux éléments sont en jeu ici:

  1. Vous ne demandez que les en-têtes de la réponse **, vous ne lisez jamais le corps de la réponse en ouvrant et en lisant (à sa fin) le ResponseStream. De ce fait, le client WebRequest laisse utilement la connexion ouverte en s’attendant à ce que vous demandiez le corps à tout moment. Tant que vous n'avez pas lu le corps de la réponse jusqu'à la fin (ce qui fermera automatiquement le flux pour vous), nettoyez et fermez le flux (ou l'instance WebRequest) ou attendez que le GC prenne sa part, votre connexion reste ouverte.

  2. Vous avez un nombre maximal par défaut de connexions actives sur le même hôte, égal à 2. Cela signifie que vous utilisez vos deux premières connexions et que vous ne les supprimez jamais. Votre client n'a donc pas la possibilité de terminer la requête suivante avant. il atteint son délai d'expiration (ce qui correspond à des millisecondes, d'ailleurs, vous l'avez donc réglé sur 0,2 seconde - la valeur par défaut devrait être correcte).

Si vous ne souhaitez pas que le corps de la réponse (ou que vous veniez de télécharger ou de poster quelque chose et que vous n'attendiez pas de réponse), fermez simplement le flux ou le client, qui le fermera pour vous.

Le moyen le plus simple de résoudre ce problème est de vous assurer que vous utilisez des blocs sur des objets jetables:

for (int i = 0; i < ops1; i++)
{
    Uri myUri = new Uri(site);
    WebRequest myWebRequest = WebRequest.Create(myUri);
    //myWebRequest.Timeout = 200;
    using (WebResponse myWebResponse = myWebRequest.GetResponse())
    {
        // Do what you want with myWebResponse.Headers.
    } // Your response will be disposed of here
}

Une autre solution consiste à autoriser 200 connexions simultanées au même hôte. Cependant, à moins que vous ne planifiiez plusieurs opérations de la même manière pour que vous ayez besoin de plusieurs connexions simultanées, cela ne vous aidera pas vraiment:

 ServicePointManager.DefaultConnectionLimit = 200;

Lorsque vous obtenez des délais d'expiration dans le code, la meilleure chose à faire est d'essayer de les recréer en dehors de votre code. Si vous ne pouvez pas, le problème réside probablement avec votre code. J'utilise habituellement cURL pour cela, ou tout simplement un navigateur Web s'il s'agit d'une simple requête GET.

** En réalité, vous demandez le premier bloc de données de la réponse, qui contient les en-têtes HTTP, ainsi que le début du corps. C'est pourquoi il est possible de lire les informations d'en-tête HTTP (telles que Content-Encoding, Set-Cookie, etc.) avant de les lire dans le flux de sortie. Lorsque vous lisez le flux, d'autres données sont extraites du serveur. La connexion de WebRequest au serveur reste ouverte jusqu'à la fin de ce flux (le ferme effectivement car il est impossible de le rechercher), fermez-le manuellement vous-même ou supprimez-le. Il y a plus à ce sujet ici .

26
Matthew Brindley

Je me souviens que j’ai eu le même problème il ya quelque temps en utilisant WCF en raison de la quantité de données que je transmettais. Je me souviens d’avoir modifié les délais d’exécution partout mais le problème persiste. Ce que j'ai finalement fait a été d'ouvrir la connexion en tant que demande de flux. Je devais changer le client et le côté serveur, mais cela fonctionne de cette façon. S'agissant d'une connexion à un flux, le serveur continuait à lire jusqu'à la fin du flux.

0
Freddy

problème de proxy peut causer cela. IIS config web a mis cela dans 

<defaultProxy useDefaultCredentials="true" enabled="true">
          <proxy usesystemdefault="True" />
        </defaultProxy>
0
Blue Clouds