2012-05-04 81 views
3

我有這樣的方法:響應流

public Stream Load(string term) 
{ 
    var url = CreateSearchUrl(term); 

    var webRequest = (HttpWebRequest)WebRequest.Create(url); 
    var webResponse = webRequest.GetResponse(); 

    return new GZipStream(webResponse.GetResponseStream(), CompressionMode.Decompress); 
} 

正如你所看到的,我返回流返回給調用者,但我不知道這是否是安全的的WebRequest方面得到由運行時處理,從而使我返回的流無效。

我可以將其轉換爲字節數組並返回一個MemoryStream甚至使用WebClient,但我只是不喜歡這個想法=)。

謝謝!

+0

運行時不會處置它。你唯一的問題是與服務器的連接不會被關閉,直到你處置它。 – Will

回答

3

沒有簡單的方法來安全地返回流,而沒有資源泄漏。主要問題是處置提供WebResponse:

public Stream Load(string term) 
{ 
    var url = CreateSearchUrl(term); 

    var webRequest = (HttpWebRequest)WebRequest.Create(url); 
    var webResponse = webRequest.GetResponse(); // whoops this doesn't get disposed! 

    return new GZipStream(webResponse.GetResponseStream(), CompressionMode.Decompress); 
} 

閉幕實際上比關閉響應流,因爲關閉WebResponse的隱式地關閉響應流更重要的是WebResponse的。

我知道獲取WebResponse與Stream一起處理的唯一方法是在放置WebResponse(以及GZipStream)時處理GZipStream的裝飾器。雖然這會工作,這是一個相當大量的代碼:

class WebResponseDisposingStream : Stream 
{ 
    private readonly WebResponse response; 
    private readonly Stream stream; 

    public WebResponseDisposingStream(WebResponse response, Stream stream) 
    { 
     if (response == null) 
      throw new ArgumentNullException("response"); 
     if (stream == null) 
      throw new ArgumentNullException("stream"); 

     this.response = response; 
     this.stream = stream; 
    } 

    public override void Close() 
    { 
     this.response.Close(); 
     this.stream.Close(); 
    } 

    // override all the methods on stream and delegate the call to this.stream 

    public override void Flush() { this.stream.Flush(); } // example delegation for Flush() 
    // ... on and on for all the other members of Stream 
} 

也許是更好的辦法是繼續傳球方式,其中使用了流的碼傳遞作爲一個代表:

public void Load(string term, Action<Stream> action) 
{ 
    var url = CreateSearchUrl(term); 

    var webRequest = (HttpWebRequest)WebRequest.Create(url); 

    using (var webResponse = webRequest.GetResponse()) 
    using (var responseStream = webResponse.GetResponseStream()) 
    using (var gzipStream = new GZipStream(responseStream, CompressionMode.Decompress)) 
    { 
     action(gzipStream); 
    } 
} 

現在,調用者只需傳入應該對Stream進行的操作。在下面的長度被打印到控制檯:

Load("test", stream => Console.WriteLine("Length=={0}", stream.Length)); 

最後一點:如果你不知道,HTTP還內置了支持壓縮。有關更多詳細信息,請參閱Wikipedia。 HttpWebRequest通過AutomaticDecompression屬性內置了對HTTP壓縮的支持。使用HTTP壓縮基本上使得壓縮對你的代碼透明,並且在HTTP工具(瀏覽器,小提琴手等)中也可以更好地工作。