【问题标题】:Response Stream from HttpWebRequest lifetime scope来自 HttpWebRequest 生命周期范围的响应流
【发布时间】:2012-05-13 14:21:59
【问题描述】:

我有这个方法:

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

谢谢!

【问题讨论】:

  • 运行时不会处理它。您遇到的唯一问题是与服务器的连接在您处理它之前不会关闭。

标签: c# stream httpwebrequest


【解决方案1】:

没有一种简单的方法可以安全地返回 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 工具(浏览器、提琴手等)配合使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多