簡體   English   中英

如何正確處理WebResponse實例?

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

通常,使用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文檔中給出的示例完全不合適。

我已經快速瀏覽了Reflector,現在可以說:

  • WebResponse是一個抽象類,它將所有關閉/處理行為委托給它的派生類。
  • HttpWebResponse ,作為你幾乎肯定在這里使用的派生類,在它的close / dispose方法中,只關心處理實際的響應流。 其余的階級國家可以留給GC的招標憐憫。

因此,只要符合以下條件,就異常處理做任何你喜歡的事情都可能是安全的:

  • 當您從try塊中的WebResponse讀取響應流時,將其包含在using塊中。
  • 如果catch塊中的WebException讀取響應流,也將它包含在using塊中。
  • 無需擔心處理WebException本身。
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而失敗。

我很確定當你有一個using語句時,無論你如何退出using塊(無論是通過異常,返回還是只是通過函數進行),都會釋放對象。

我懷疑如果讓它離開使用塊,你會發現WebException中的對象已被處理掉了。

請記住,處置對象不一定會阻止以后訪問它。 嘗試稍后調用方法可能是不可預測的,導致它自己或非常奇怪的行為的異常(因此我不推薦它)。 但即使你丟棄它,即使仍然有很大一部分對象仍留在垃圾收集器中,因此仍可訪問。 dispose的目的通常是清理資源句柄(就像在這種情況下是活動的TCP連接),出於性能原因,在垃圾收集器找到它們之前,您無法實際放置。 我只是提到這一點,以澄清它的處理並不是相互排斥的,而是提及它的例外情況。

在拋出WebException之前, HttpWebRequest內部使內存流脫離底層網絡流,因此沒有與WebException.Response返回的WebResponse關聯的非托管資源。

這使得不必在其上調用Dispose() 實際上,嘗試處置WebException.Response可能會導致頭痛和問題,因為您的代碼調用者可能會嘗試讀取與之關聯的屬性。

但是,您應該處置您擁有的任何IDisposable對象是一個好習慣。 如果您決定這樣做,請確保您沒有代碼,具體取決於能否讀取WebException.Response屬性和/或其流。 最好的方法是處理異常並拋出新類型的異常,以便在可能的情況下不會將WebException泄漏給調用者。

並且還考慮轉移到替換HttpWebRequest HttpClient

免責聲明:不提供任何保證。

一個非常有趣的問題(雖然值得指出,當您退出使用時,WebResponse對象被處理掉)。 我的直覺是,只要您不嘗試對其進行任何“操作”操作,您就可以引用此處理的WebResponse對象並不重要。

可能仍然可以訪問實例上的某些屬性以進行日志記錄(例如ResponseUri)而不會收到ObjectDisposedException ,但異常所持有的整體引用不存在,因此您可以繼續使用該實例。

我有興趣看看別人怎么說。

我在EF DB連接中遇到類似的情況。

所以我實際上創建了一個連接列表。

在游戲結束時,我循環處理所有這些。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM