Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
307 views
in Technique[技术] by (71.8m points)

.net - Is there a correct way to dispose of a httpwebrequest?

I am using a HttpWebRequest, and am disposing of the response stream. Is there a correct method of disposing of the HttpWebRequest, as it does not contain a close or dispose method?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I had a similar question, and the answers here did not give me the information I needed. So even though there is an accepted answer, I'm going to add what I've learned to help the next guy.

1) As some of the other answers mention, you can use using for the streams returned from HttpWebRequest/WebRequest. This is just good standard c# programming.

But it doesn't really address the OP's question (or mine), which was about the disposing of the HttpWebRequest object itself.

2) Despite the fact that the function to acquire an HttpWebRequest is named 'Create,' there is no matching Destroy, Close, Dispose, or any other mechanism available to free the resources from the created object.

This is basically the currently accepted answer.

3) But there is an implication among all the answers here that (other than the streams) there isn't anything important left hanging around that needs to be closed. And that is not entirely correct.

Using ProcMon, you can see the TCP Connect, TCP Send and TCP Receive that occur when you call GetResponse(). This is what I would expect to see. But when does the TCP Disconnect occur? My assumption was that this would happen either after you finished receiving the response, or at worst when the object gets GC'ed. But the reality is more interesting.

Instead, the TCP connection remains active for exactly 2 minutes after the call. My first thought was that's just how long it takes for the GC to get around to it, but nope. You can sit there in a GC.Collect() loop for those 2 minutes, and it doesn't let go until the 2 minutes are up. This keeps the connection open on both the client and the server, and causes (some) additional network traffic for those 2 minutes to keep the connection alive.

Another interesting thing is that even though you are calling 'Create', that doesn't mean another TCP connection necessarily gets created. For instance, consider this:

static void Doit(string domain)
{
    HttpWebRequest hr = (HttpWebRequest)WebRequest.Create(domain);

    using (HttpWebResponse response = (HttpWebResponse)hr.GetResponse())
        using (Stream receiveStream = response.GetResponseStream())
            using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8))
                Console.WriteLine(readStream.ReadToEnd());
}

Now, if I call this with:

Doit("http://www.foo.bar");

It will create 1 TCP connection. It will stay active for 2 minutes (or until the program exits). But what if I do this:

Doit("http://www.foo.bar");
Thread.Sleep(20000);
Doit("http://www.foo.bar");

Now it will create 1 connection for the first call, then reuse that connection for the second call. Meaning the TCP connection will stay active for 2:20 minutes total. So even though we are calling 'Create,' it's not creating a connection from scratch.

Mostly this is a good thing. Making a connection (especially an HTTPS connection) can be an expensive process. A system that automatically avoids that for you is (probably) a good thing. That way you can efficiently retrieve the html for a web page, then any of the related support files (css, img files, etc) without having to go through the connect process each time.

But what if the server you are connecting to only supports a limited number of connections? Leaving a connection tied up like this for no good reason could be a real problem. Or perhaps for security reasons, you can't be leaving connections open for that long? Or maybe you're just anal and want to shut the thing down as soon as you are done with it.

For these cases, you can experiment with HttpWebRequest.KeepAlive. Setting this to false (the default is true) causes each of the examples above to each use their own connection, shutting them down as soon as you are done. The entire Connect/Send/Receive/Disconnect process can thus complete in less than a second.

FYI:

  • While you can use WebRequest.InitializeLifetimeService to get an ILease, changing the values on the lease does not affect the timeouts here.
  • Instead of using WebRequest, you can use WebClient, which does support Dispose. However the underlying TCP connection still hangs around for 2 minutes even after calling Dispose.

In conclusion: Saying that you don't need to worry about shutting down an HttpWebClient may be generally true, but there are implications you might want to be aware of. There are good reasons for this behavior, but you cannot decide whether this is good for your particular application if you don't know it is happening.

FWIW


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...