我有这种方法:

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,但我只是不喜欢这个想法=)。

谢谢!

最佳答案

没有一种简单的方法可以安全地返回Stream而又不会造成资源泄漏。主要问题是配置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一起处理的唯一方法是在GZipStream周围实现一个装饰器,该装饰器在处理WebResponse(以及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
}


也许更好的方法是延续传递样式,其中使用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工具(浏览器,提琴手等)一起更好地工作。

关于c# - HttpWebRequest生存期范围的响应流,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10442061/

10-12 15:27