42 Stimmen

Gibt es einen korrekten Weg, um eine httpwebrequest zu entsorgen?

Ich verwende eine HttpWebRequest und entledige mich des Antwortstroms. Gibt es eine korrekte Methode zur Beseitigung des HttpWebRequest da sie keine close- oder dispose-Methode enthält?

54voto

David Wohlferd Punkte 6508

Ich hatte eine ähnliche Frage, und die Antworten hier gaben mir nicht die Informationen, die ich brauchte. Obwohl es also eine akzeptierte Antwort gibt, werde ich hinzufügen, was ich gelernt habe, um dem Nächsten zu helfen.

1) Wie in einigen der anderen Antworten erwähnt, können Sie using für die Streams, die von HttpWebRequest/WebRequest zurückgegeben werden. Dies ist nur gut Standard c# Programmierung.

Aber es nicht wirklich auf die OP-Frage (oder meine), die über die Beseitigung der HttpWebRequest-Objekt selbst war.

2) Trotz der Tatsache, dass die Funktion zur Erfassung einer HttpWebRequest "Create" heißt, gibt es keinen passenden Destroy-, Close-, Dispose- oder sonstigen Mechanismus, um die Ressourcen des erstellten Objekts freizugeben.

Dies ist im Grunde die derzeit akzeptierte Antwort.

3) Aber alle Antworten hier implizieren, dass es (abgesehen von den Strömen) nichts Wichtiges mehr gibt, das in der Gegend herumliegt. braucht geschlossen werden. Und das ist nicht ganz richtig.

Verwendung von ProcMon können Sie die TCP Connect , TCP Send y TCP Receive die auftreten, wenn Sie die GetResponse() . Das ist es, was ich erwarten würde, zu sehen. Aber wann ist die TCP Disconnect auftreten? Ich bin davon ausgegangen, dass dies entweder nach dem Empfang der Antwort oder schlimmstenfalls, wenn das Objekt GC'ed wird, geschehen würde. Aber die Realität ist interessanter.

Stattdessen bleibt die TCP-Verbindung nach dem Anruf noch genau 2 Minuten lang aktiv. Mein erster Gedanke war, dass es nur so lange dauert, bis der GC sich damit befasst, aber nein. Sie können dort in einer GC.Collect()-Schleife für diese 2 Minuten sitzen, und es wird nicht losgelassen, bis die 2 Minuten vorbei sind. Dies hält die Verbindung sowohl auf dem Client als auch auf dem Server offen und verursacht (etwas) zusätzlichen Netzwerkverkehr für diese 2 Minuten, um die Verbindung aufrechtzuerhalten.

Interessant ist auch, dass der Aufruf von "Create" nicht unbedingt bedeutet, dass eine weitere TCP-Verbindung hergestellt wird. Betrachten Sie zum Beispiel dies:

static void Doit(string domain)
{
    HttpWebRequest hr = (HttpWebRequest)WebRequest.Create(domain);

    using (HttpWebResponse response = (HttpWebResponse)hr.GetResponse())
        using (Stream receiveStream = response.GetResponseStream())
            using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8))
                Console.WriteLine(readStream.ReadToEnd());
}

Wenn ich das jetzt mit aufrufe:

Doit("http://www.foo.bar");

Es wird 1 TCP-Verbindung hergestellt. Sie bleibt für 2 Minuten aktiv (oder bis das Programm beendet wird). Aber was ist, wenn ich dies tue:

Doit("http://www.foo.bar");
Thread.Sleep(20000);
Doit("http://www.foo.bar");

Jetzt wird 1 Verbindung für den ersten Anruf hergestellt, dann Wiederverwendung diese Verbindung für den zweiten Anruf. Das bedeutet, dass die TCP-Verbindung insgesamt 2:20 Minuten lang aktiv bleibt. Obwohl wir also "Create" aufrufen, wird die Verbindung nicht von Grund auf neu erstellt.

Meistens ist das eine gute Sache. Die Herstellung einer Verbindung (insbesondere einer HTTPS-Verbindung) kann ein teurer Prozess sein. Ein System, das dies automatisch für Sie vermeidet, ist (wahrscheinlich) eine gute Sache. Auf diese Weise können Sie auf effiziente Weise die HTML-Datei für eine Webseite abrufen und dann alle zugehörigen Unterstützungsdateien (css, img-Dateien usw.), ohne jedes Mal den Verbindungsprozess durchlaufen zu müssen.

Was aber, wenn der Server, mit dem Sie sich verbinden wollen, nur eine begrenzte Anzahl von Verbindungen unterstützt? Wenn eine Verbindung ohne triftigen Grund bestehen bleibt, könnte das ein echtes Problem darstellen. Oder vielleicht können Sie aus Sicherheitsgründen die Verbindungen nicht so lange offen lassen? Vielleicht sind Sie aber auch einfach nur pingelig und wollen das Ding abschalten, sobald Sie damit fertig sind.

Für diese Fälle können Sie experimentieren mit HttpWebRequest.KeepAlive . Diese Einstellung auf false (der Standardwert ist true ) führt dazu, dass jedes der obigen Beispiele eine eigene Verbindung verwendet und diese beendet wird, sobald Sie fertig sind. Der gesamte Vorgang "Verbinden/Senden/Empfangen/Trennen" kann so in weniger als einer Sekunde abgeschlossen werden.

ZU IHRER INFORMATION:

  • Sie können zwar WebRequest.InitializeLifetimeService verwenden, um eine ILease zu erhalten, aber das Ändern der Werte für den Lease hat hier keine Auswirkungen auf die Timeouts.
  • Anstelle von WebRequest können Sie auch WebClient verwenden, der Dispose unterstützt. Die zugrunde liegende TCP-Verbindung bleibt jedoch auch nach dem Aufruf von Dispose noch 2 Minuten lang bestehen.

Zusammengefasst: Die Aussage, dass Sie sich keine Gedanken über das Herunterfahren eines HttpWebClients machen müssen, mag im Allgemeinen zutreffen, aber es gibt Auswirkungen, die Sie beachten sollten. Es gibt gute Gründe für dieses Verhalten, aber Sie können nicht entscheiden, ob dies für Ihre spezielle Anwendung gut ist, wenn Sie nicht wissen, dass es geschieht.

FWIW

3 Stimmen

Vielen Dank für diesen ausführlichen Einblick! Ich hatte eine komplexe REST-API zufällig werfen Verbindung abgebrochen/Verbindung ferngesteuert geschlossen Fehler bei mir. Diese API (services.mobile.de) wird immer so verwendet, dass man eine Reihe von Anfragen an sie stellt. Es stellte sich heraus, dass es nicht nett mit HttpWebRequest wiederverwendete Verbindungen spielen: Sie schließt die Verbindung, wann immer sie es für nötig hält, was zu zufälligen Fehlern führt. Nun, da ich gesetzt .KeepAlive a false ist alles in Ordnung!

3 Stimmen

Es stellte sich heraus, dass die WebRequest.ServicePoint.MaxIdleTime ist ebenfalls wichtig: Wenn Sie eine Reihe von Anfragen starten, sollte dies die maximale Leerlaufzeit des Servers nicht überschreiten, da Sie sonst versuchen, eine bereits geschlossene Verbindung serverseitig wiederherzustellen, auch wenn .KeepAlive es false .

1 Stimmen

Gute ifnfo! Ich danke Ihnen. Die zugrunde liegende TCP-Verbindung, die bis zu vier Minuten aufrechterhalten wird, ist eher auf den Netzwerk-Stack zurückzuführen. Dies wird als "Wartezeit" bezeichnet und ist ein normales Verhalten für eine TCP-Verbindung, die offen bleibt, falls der Client sie schließt, bevor der Server mit ihr fertig ist. Auf diese Weise können beide Seiten die Verbindung sicher und koordiniert schließen. Siehe StackExchange-Antwort unter networkengineering.stackexchange.com/q/19581 .

43voto

John Saunders Punkte 159011

Wenn die Klasse besondere Anforderungen an die Entsorgung hätte, hätte sie IDisposable implementiert. Da sie IDisposable nicht implementiert, können Sie davon ausgehen, dass Sie nichts Besonderes tun müssen.

1 Stimmen

Es gibt Szenarien, in denen es nicht sofort aus dem Rahmen fällt - vor allem, wenn Sie mehrere Webanfragen innerhalb kurzer Zeit erstellen. Wenn Sie es entsorgen müssen, übergeben Sie es einfach an IDisposable und rufen dann die Dispose() Methode an.

0 Stimmen

@mee Das macht nichts. HttpWebRequest implementiert nicht IDisposable .

4voto

Kevin M Punkte 76

Sie können verwenden:

    var webRequest = WebRequest.Create(ActionUrl)
    using (var webResponse = webRequest.GetResponse())
    {}

für Ihre Implementierung. Wenn ich die WebRequest-Klasse verwendet habe, um mehrere Anfragen in einem sehr kurzen Zeitrahmen abzufeuern, ist das Einschließen der GetResponse() in einen using-Block das, was die App vor dem Aufhängen bewahrt.

3voto

Joshua Punkte 895

HttpwebRequest implementiert IDisposable nicht, da es einen Stream erstellen kann, der IDisposable implementiert. Daher sollten Sie sich nicht um die Entsorgung kümmern.

Wenn Sie jedoch besorgt sind, sollten Sie WebClient verwenden, der IDisposable ist:

using (WebClient c = new WebClient())
{
using (Stream stream = c.OpenRead(url))
{
//
}
}

-3voto

HttpWebRequest implementiert IDisposable nicht, so dass es nicht erforderlich ist, zu entsorgen. Setzen Sie einfach das HttpWebRequest-Objekt auf null, sobald Sie damit fertig sind.

Ich hoffe, es hilft

18 Stimmen

Warum auf Null setzen? Lassen Sie es aus dem Bereich gehen ist genug für die GC, um es abholen.....

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X