简体   繁体   English

如何正确处理WebResponse实例?

[英]How to properly dispose of a WebResponse instance?

Normally, one writes code something like this to download some data using a WebRequest. 通常,使用WebRequest编写类似这样的代码来下载一些数据。

using(WebResponse resp = request.GetResponse())  // WebRequest request...
   using(Stream str = resp.GetResponseStream())  
      ; // do something with the stream str

Now if a WebException is thrown, the WebException has a reference to the WebResponse object, which may or may not have Dispose called (depending on where the exception has happened, or how the response class is implemented) - I don't know. 现在,如果抛出WebException,WebException会引用WebResponse对象,该对象可能会或可能不会调用Dispose(取决于发生异常的位置,或者响应类的实现方式) - 我不知道。

My question is how one is supposed to deal with this. 我的问题是如何处理这个问题。 Is one supposed to be coding very defensively, and dispose of the response in the WebException object (that would be a little weird, as WebException is not IDisposable). 是否应该编写一个非常防御性的编码,并在WebException对象中处理响应(这有点奇怪,因为WebException不是IDisposable)。 Or is one supposed to ignore this, potentially accessing a disposed object or never disposing an IDisposable object? 或者是否应该忽略这一点,可能访问已处置的对象或从不处置IDisposable对象? The example given in the MSDN documentation for WebException.Response is wholly inadequate. WebException.Response的MSDN文档中给出的示例完全不合适。

I have had a quick peek with Reflector, and can now say: 我已经快速浏览了Reflector,现在可以说:

  • WebResponse , being an abstract class, delegates all its closing/disposing behaviour to its derived classes. WebResponse是一个抽象类,它将所有关闭/处理行为委托给它的派生类。
  • HttpWebResponse , being the derived class you are almost certainly using here, in its close/dispose methods, is only concerned with disposing the actual response stream. HttpWebResponse ,作为你几乎肯定在这里使用的派生类,在它的close / dispose方法中,只关心处理实际的响应流。 The rest of the class state can be left to the GC's tender mercies. 其余的阶级国家可以留给GC的招标怜悯。

It follows that it's probably safe to do whatever you like with regard to exception handling, as long as: 因此,只要符合以下条件,就异常处理做任何你喜欢的事情都可能是安全的:

  • When you read the response stream from WebResponse in the try block, enclose it in a using block. 当您从try块中的WebResponse读取响应流时,将其包含在using块中。
  • If you read the response stream from WebException in the catch block, enclose it in a using block as well. 如果catch块中的WebException读取响应流,也将它包含在using块中。
  • There is no need to worry about disposing of WebException itself. 无需担心处理WebException本身。
using (var x = GetObject()) {
     statements;
}

is (almost) equivalent to 是(几乎)相当于

var x = GetObject();
try {
    statements;
}
finally {
     ((IDisposable)x).Dispose();
}

so your object will always be disposed. 所以你的对象将永远处理掉。

This means that in your case 这意味着在你的情况下

try {
    using (WebResponse resp = request.GetResponse()) {
        something;
    }
}
catch (WebException ex) {
    DoSomething(ex.Response);
}

ex.Response will be the same object as your local resp object, which is disposed when you get to the catch handler. ex.Response将是与本地resp对象相同的对象,当你到达catch处理程序时它会被释放。 This means that DoSomething is using a disposed object, and will likely fail with an ObjectDisposedException. 这意味着DoSomething正在使用已处置的对象,并且可能会因ObjectDisposedException而失败。

I'm pretty sure that when you have a using statement the object is disposed, regardless of how you exit the using block (Be it via exception, return or simply progressing through the function). 我很确定当你有一个using语句时,无论你如何退出using块(无论是通过异常,返回还是只是通过函数进行),都会释放对象。

I suspect you'll find that the object inside the WebException has already been disposed if you let it leave the using block. 我怀疑如果让它离开使用块,你会发现WebException中的对象已被处理掉了。

Remember, disposing of an object doesn't necessarily prevent accessing it later. 请记住,处置对象不一定会阻止以后访问它。 It can be unpredictable to try to call methods on it later, causing exceptions of it's own or very weird behavior (And hence I wouldn't recommend it). 尝试稍后调用方法可能是不可预测的,导致它自己或非常奇怪的行为的异常(因此我不推荐它)。 But even still a large portion of the object is still left behind for the garbage collector even if you dispose it, and hence is still accessible. 但即使你丢弃它,即使仍然有很大一部分对象仍留在垃圾收集器中,因此仍可访问。 The purpose of the dispose is typically to clean up resource handles (Like in this case active TCP connections) that for performance reasons you can't realistically leave laying around until the garbage collector finds them. dispose的目的通常是清理资源句柄(就像在这种情况下是活动的TCP连接),出于性能原因,在垃圾收集器找到它们之前,您无法实际放置。 I only mention this to clarify that it's not mutually exclusive for it to be disposed and the exception to hold a reference to it. 我只是提到这一点,以澄清它的处理并不是相互排斥的,而是提及它的例外情况。

HttpWebRequest internally makes a memory stream off the underlying network stream before throwing WebException , so there is no unmanaged resource associated with the WebResponse returned from WebException.Response . 在抛出WebException之前, HttpWebRequest内部使内存流脱离底层网络流,因此没有与WebException.Response返回的WebResponse关联的非托管资源。

This makes it unnecessary to call Dispose() on it. 这使得不必在其上调用Dispose() In fact, trying to dispose WebException.Response can cause headache and issues because you may have callers of your code that is attempting to read properties associated with it. 实际上,尝试处置WebException.Response可能会导致头痛和问题,因为您的代码调用者可能会尝试读取与之关联的属性。

However it is a good practice that you should dispose any IDisposable objects you own. 但是,您应该处置您拥有的任何IDisposable对象是一个好习惯。 If you decide to do so, make sure you don't have code depending on being able to read WebException.Response properties and/or its stream. 如果您决定这样做,请确保您没有代码,具体取决于能否读取WebException.Response属性和/或其流。 The best way would be you handle the exception and throw new type of exception so that you don't leak WebException up to the caller when possible. 最好的方法是处理异常并抛出新类型的异常,以便在可能的情况下不会将WebException泄漏给调用者。

And also consider moving to HttpClient which replaces HttpWebRequest . 并且还考虑转移到替换HttpWebRequest HttpClient

Disclaimer: No warranty implied. 免责声明:不提供任何保证。

A very interesting question (although worth pointing out that the WebResponse object will have been disposed as you exit the using). 一个非常有趣的问题(虽然值得指出,当您退出使用时,WebResponse对象被处理掉)。 My gut feeling is that it doesn't really matter that you've got a reference to this disposed WebResponse object as long as you don't try to do anything "operational" with it. 我的直觉是,只要您不尝试对其进行任何“操作”操作,您就可以引用此处理的WebResponse对象并不重要。

You can probably still access certain properties on the instance for logging purposes (such as the ResponseUri) without getting an ObjectDisposedException , but overall reference held by the exception is not there so you can continue using the instance. 可能仍然可以访问实例上的某些属性以进行日志记录(例如ResponseUri)而不会收到ObjectDisposedException ,但异常所持有的整体引用不存在,因此您可以继续使用该实例。

I'd be interested to see what others say. 我有兴趣看看别人怎么说。

I get similar cases in EF DB connections. 我在EF DB连接中遇到类似的情况。

So i actually create a connections list. 所以我实际上创建了一个连接列表。

At the end of game , i loop dispose all of them. 在游戏结束时,我循环处理所有这些。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM