There isn't an easy way to safely return the Stream without having resource leaks. The main issue is disposing the 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);
}
Closing the WebResponse is actually more important than closing the response stream, since closing the WebResponse implicitly closes the response stream.
The only way I know of getting the WebResponse to be disposed with the Stream would be to implement a decorator around the GZipStream that disposed of the WebResponse (as well as the GZipStream) when it is disposed. Although this would work, it is quite a lot of code:
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
}
Perhaps a better approach would be a continuation passing style where the code that uses the Stream is passed in as an delegate:
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);
}
}
Now the caller simply passes in what should be done with the Stream. In the following the length is printed to the console:
Load("test", stream => Console.WriteLine("Length=={0}", stream.Length));
One final note: In case you're not aware, HTTP has built-in support for compression. See Wikipedia for more details. The HttpWebRequest has built-in support for HTTP compression via the AutomaticDecompression property. Using the HTTP compression basically makes the compression transparent to your code and also works better with HTTP tooling (browsers, fiddler, etc).