如何正确处理WebResponse实例?

时间:2009-12-11 10:57:41

标签: c# .net idisposable webresponse

通常,人们会使用WebRequest下载一些类似的代码。

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

现在,如果抛出WebException,WebException会引用WebResponse对象,该对象可能会也可能不会调用Dispose(取决于发生异常的位置,或者响应类是如何实现的) - 我不是知道。

我的问题是如何处理这个问题。是否应该编写一个非常防御性的编码,并在WebException对象中处理响应(这有点奇怪,因为WebException不是IDisposable)。或者是否应该忽略这一点,可能访问已处置的对象或从不处置IDisposable对象? WebException.Response的MSDN文档中给出的示例完全不合适。

6 个答案:

答案 0 :(得分:15)

我快速浏览了Reflector,现在可以说:

  • WebResponse,作为一个抽象类,将其所有关闭/处置行为委托给其派生类。
  • HttpWebResponse,作为派生类,你几乎肯定在这里使用它的close / dispose方法,只关心处理实际的响应流。其余的阶级状态可以留给GC的怜悯。

因此,只要符合以下条件,就可以安全地做任何你喜欢的异常处理:

  • 当您从WebResponse块中的try读取响应流时,请将其封装在using块中。
  • 如果您从WebException块中的catch读取了响应流,请将其也包含在using块中。
  • 无需担心自己处置WebException

答案 1 :(得分:3)

using (var x = GetObject()) {
     statements;
}

(差不多)等同于

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

所以你的对象将永远被处理掉。

这意味着在您的情况下

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

ex.Response将与您的本地resp对象是同一个对象,当您到达catch处理程序时会将其放置。这意味着DoSomething正在使用已处置的对象,并且可能会因ObjectDisposedException而失败。

答案 2 :(得分:2)

我很确定当你有一个using语句时,无论你如何退出using块(无论是通过异常,返回还是只是通过函数进行),都会处理该对象。

我怀疑如果让它离开使用块,你会发现WebException中的对象已被处理掉。

请记住,处置对象并不一定会阻止以后访问它。尝试稍后调用方法可能是不可预测的,导致它自己或非常奇怪的行为的异常(因此我不推荐它)。但即使你丢弃它,即使仍然有很大一部分对象仍留在垃圾收集器中,因此仍可访问。 dispose的目的通常是清理资源句柄(就像在这种情况下是活动的TCP连接),出于性能原因,在垃圾收集器找到它们之前,您无法实际放置。我只是提到这一点,以澄清它的处理并不是相互排斥的,而是提及它的例外。

答案 3 :(得分:2)

HttpWebRequest在抛出WebException之前在内部从底层网络流中创建内存流,因此没有与WebResponse返回的WebException.Response关联的非托管资源。

这使得无需在其上调用Dispose()。实际上,尝试处置WebException.Response可能会导致头痛和问题,因为您的代码调用者可能会尝试读取与之关联的属性。

但是,您应该处置您拥有的任何IDisposable个对象,这是一个好习惯。如果您决定这样做,请确保您没有代码,具体取决于能够阅读WebException.Response属性和/或其流。最好的方法是处理异常并抛出新类型的异常,以便在可能的情况下不会将WebException泄漏给调用者。

并考虑转移到HttpClient,取代HttpWebRequest

免责声明:不提供任何保证。

答案 4 :(得分:0)

一个非常有趣的问题(虽然值得指出,当您退出使用时,WebResponse对象处理掉)。我的直觉是,只要您不尝试对其进行任何“操作”操作,您就可以引用此处理的WebResponse对象并不重要。

可能仍然可以访问实例上的某些属性以进行日志记录(例如ResponseUri)而不会获得ObjectDisposedException,但异常所持有的整体引用不存在,所以您可以继续使用该实例。

我有兴趣看看别人怎么说。

答案 5 :(得分:0)

我在EF DB连接中遇到类似的情况。

所以我实际创建了一个连接列表。

在游戏结束时,我循环处理所有这些。