Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly dispose of a WebResponse instance?

Normally, one writes code something like this to download some data using a WebRequest.

using(WebResponse resp = request.GetResponse())  // WebRequest request...
   using(Stream str = resp.GetResponseStream())  
      ; // do something with the stream str

Now if a WebException is thrown, the WebException has a reference to the WebResponse object, which may or may not have Dispose called (depending on where the exception has happened, or how the response class is implemented) - I don't know.

My question is how one is supposed to deal with this. Is one supposed to be coding very defensively, and dispose of the response in the WebException object (that would be a little weird, as WebException is not IDisposable). Or is one supposed to ignore this, potentially accessing a disposed object or never disposing an IDisposable object? The example given in the MSDN documentation for WebException.Response is wholly inadequate.

like image 279
Marcus Avatar asked Dec 11 '09 10:12

Marcus


3 Answers

I have had a quick peek with Reflector, and can now say:

  • WebResponse, being an abstract class, delegates all its closing/disposing behaviour to its derived classes.
  • HttpWebResponse, being the derived class you are almost certainly using here, in its close/dispose methods, is only concerned with disposing the actual response stream. The rest of the class state can be left to the GC's tender mercies.

It follows that it's probably safe to do whatever you like with regard to exception handling, as long as:

  • When you read the response stream from WebResponse in the try block, enclose it in a using block.
  • If you read the response stream from WebException in the catch block, enclose it in a using block as well.
  • There is no need to worry about disposing of WebException itself.
like image 109
Christian Hayter Avatar answered Sep 23 '22 07:09

Christian Hayter


using (var x = GetObject()) {      statements; } 

is (almost) equivalent to

var x = GetObject(); try {     statements; } finally {      ((IDisposable)x).Dispose(); } 

so your object will always be disposed.

This means that in your case

try {     using (WebResponse resp = request.GetResponse()) {         something;     } } catch (WebException ex) {     DoSomething(ex.Response); } 

ex.Response will be the same object as your local resp object, which is disposed when you get to the catch handler. This means that DoSomething is using a disposed object, and will likely fail with an ObjectDisposedException.

like image 43
erikkallen Avatar answered Sep 24 '22 07:09

erikkallen


HttpWebRequest internally makes a memory stream off the underlying network stream before throwing WebException, so there is no unmanaged resource associated with the WebResponse returned from WebException.Response.

This makes it unnecessary to call Dispose() on it. In fact, trying to dispose WebException.Response can cause headache and issues because you may have callers of your code that is attempting to read properties associated with it.

However it is a good practice that you should dispose any IDisposable objects you own. If you decide to do so, make sure you don't have code depending on being able to read WebException.Response properties and/or its stream. The best way would be you handle the exception and throw new type of exception so that you don't leak WebException up to the caller when possible.

And also consider moving to HttpClient which replaces HttpWebRequest.

Disclaimer: No warranty implied.

like image 25
Sunghwa Jin Avatar answered Sep 23 '22 07:09

Sunghwa Jin