HttpWebRequest and IDisposable

M

Mark Rae

Hi,

The following code works:

HttpWebRequest objRequest = null;
try
{
HttpWebRequest objRequest =
(HttpWebRequest)WebRequest.Create("http://www.microsoft.com");
using (HttpWebResponse objResponse =
(HttpWebResponse)objRequest.GetResponse())
{
// do something...
}
}
catch
{
throw;
}
finally
{
if (objWebRequest != null)
{
objWebRequest = null;
}
}

However, the following code doesn't work:

using (HttpWebRequest objRequest =
(HttpWebRequest)WebRequest.Create("http://www.microsoft.com"))
{
using (HttpWebResponse objResponse =
(HttpWebResponse)objRequest.GetResponse())
{
// do something...
}
}

because HttpWebRequest is not implicitly convertible to IDisposable.

I'm curious to know if there is a way to use HttpWebRequest with the
"using" - just for my own interest, really...

Any assistance gratefully received.

Mark
 
M

Marc Gravell

(Following relates to all general variable usage; not specifically to
web-request)

Well, what do you think your code does?

catch {
throw;
}

Does nothing, as it would have been thrown anyway... so that leaves the
finally:

finally
{
if (objWebRequest != null)
{
objWebRequest = null;
}
}

Interestingly, because you read the variable (in the test), this
technically *extends* the lifetime of the variable. Otherwise it would
be eligible for collection earlier. I guess it all depends on whether
objWebRequest is a field (scoped by the class) or a variable (scoped by
the method). If a field, fine: just remove the catch; if a variable,
then just let it go out of scope; it will actually be avaiable for GC
as soon as your last "read". In a garbage collected world, the "using"
and "finally" patterns are mainly for timely disposal of resources. The
above looks more like COM / VB6, but you don't need this with C#
variables.

Marc
 
D

Dave Sexton

Hi Mark,

However, the following code doesn't work:

using (HttpWebRequest objRequest =
(HttpWebRequest)WebRequest.Create("http://www.microsoft.com"))
{
using (HttpWebResponse objResponse =
(HttpWebResponse)objRequest.GetResponse())
{
// do something...
}
}

because HttpWebRequest is not implicitly convertible to IDisposable.

I'm curious to know if there is a way to use HttpWebRequest with the
"using" - just for my own interest, really...

I think it's strange that WebRequest doesn't implement IDisposable since it
can create a Stream, which does implement IDisposable. Unfortunately, there
is no way for you to use the "using" statement with this class, although you
probably shouldn't worry about that anyway.

Instead, you may want to use WebClient, which is IDisposable:

using (WebClient client = new WebClient())
{
using (Stream stream = client.OpenRead(url))
{
// etc.
}
}
 
M

Mark Rae

I guess it all depends on whether objWebRequest is a field
(scoped by the class) or a variable (scoped by the method).

It has nothing whatsoever to do with that at all - did you actually*read* my
original post...?

Dave Sexton understood it and replied accordingly - you might want to have a
read at his...
 
M

Mark Rae

I think it's strange that WebRequest doesn't implement IDisposable since
it can create a Stream, which does implement IDisposable.

I was / am of that opinion too - hence my original post...
Unfortunately, there is no way for you to use the "using" statement with
this class,

That's what I thought - thanks for the clarification.
although you probably shouldn't worry about that anyway.

Indeed not - like I said, I merely posted the question for my own interest,
not because I had some burning need to use "using" with HttpWebRequest...
:)

I find that by now, after quite a few years of working with the .NET
Framework, most of it makes reasonably intuitive sense, so when I come
across something like this which seems unusual, I'm naturally curious about
it...
Instead, you may want to use WebClient, which is IDisposable:

using (WebClient client = new WebClient())
{
using (Stream stream = client.OpenRead(url))
{
// etc.
}
}

That seems like a good suggestion - so, am I right in thinking that
WebClient performs the functions of both HttpWebRequest and
HttpWebResponse...?
 
M

Mark Rae

WebClient does, but it's a wrapper over the whole mechanism designed to
simplify and doesn't provide access to all the lower-level "stuff" that's
in
HttpWebRequest and HttpWebResponse.

Thanks for that.
 
M

Marc Gravell

did you actually*read* my original post...?
Yes thanks very much for asking. You said (essentially) "this works". I
was observing that it may well work, but it achieves nothing.

Marc
 
M

Marc Gravell

Additional:
I think it's strange that WebRequest doesn't implement IDisposable since it
can create a Stream, which does implement IDisposable.

Just because something is capable of creating and returning an
IDisposable object does not imply that it is *itself* IDisposable. Any
objects created from this class should, of course, be disposed
correctly.
I have run reflector over WebClient, and even in this case it only
picks up IDisposable as an arftifact of the base Component class - it
doesn't actually provide any Dispose() logic of its own. Of course, I
would still be "using" WebClient.

The *very* curious thing (to turn this all on its head) is that
HttpWebRequest *does* have some IDisposable fields - a few internal
streams and a timer (possibly more; stopped looking). Unless these are
all guaranteed to be cleaned up before leaving encapsulating methods,
you would *expect* HttpWebRequest to be disposable, and hence the
original "why doesn't this work" would be completely valid (and
WebClient would have something interesting to do in *its* Dispose()
method). All very interesting.

My original point, however, still stands: setting something to null is
a very different beast to Dispose()ing it; if it isn't IDisposable,
then it doesn't need to be Dispose()d, so you can't be "using" it.

Marc
 
M

Mark Rae

setting something to null is a very different beast to Dispose()ing it;

That's right.
if it isn't IDisposable, then it doesn't need to be Dispose()d,

Er, surely if it isn't IDisposable, then it *can't* be Dispose()d,
irrespective of whether it needs to be or not...???
so you can't be "using" it.

Er, right again... And precisely because HttpWebRequest isn't IDisposable, I
wasn't "using" it, hence the reason I was explicitly setting it to null in
finally{...}

My original post centred on my surprise that HttpWebRequest *isn't*
IDisposable...
 
D

Dave Sexton

Hi Marc,
can create a Stream, which does implement IDisposable.

Just because something is capable of creating and returning an
IDisposable object does not imply that it is *itself* IDisposable

It had seemed obvious to me, and still does, that HttpWebRequest should
implement IDisposable not because it simply may "return" a Stream, but
because it "composites" one, and Stream is certainly IDisposable. I used
the term "create", not "return", but in hindsight I should have wrote
"composites" :)

The point being that HttpWebRequest manages the lifetime of the Stream.
GetRequestStream is available, but doesn't have to be called. A Stream is
created to make the request, but because it's still referenced by the
HttpWebRequest object for when GetResponse is called, it doesn't make sense
to me that the caller should be responsible to dispose of the Stream. How
should the caller know when HttpWebRequest is done using the Stream? After
all, the implementation details shouldn't be known to the caller but this
pattern implies them, such as that GetResponse must ensure that the entire
Stream is read before returning to the caller or else disposing it early
would be problematic.

I hope that clears up :)

<snip>

Interesting, about the internals of WebClient. I bet the developers
implemented IDisposable for future use (since HttpWebRequest should
implement IDisposable). I wonder if they tried to implement it and went,
"Un oh. Who designed HttpWebRequest?" :)
 
M

Marc Gravell

My original post centred on my surprise that HttpWebRequest *isn't*
IDisposable...

I've just re-read the OP very carefully, and if this was your intent it
isn't exactly very clear... but for the sake of agreement I'll take
that at face value... ;-p

But I think we (the 3 of us, at least) all now agree that it *should*
work the way you suggest, but it can't. It wouldn't be the first or
last such, but it was an intersting question.

Marc
 
M

Mark Rae

I've just re-read the OP very carefully, and if this was your intent it
isn't exactly very clear... but for the sake of agreement I'll take
that at face value... ;-p

In which case, that's my fault, and I apologise for the lack of clarity...
But I think we (the 3 of us, at least) all now agree that it *should*
work the way you suggest, but it can't. It wouldn't be the first or
last such, but it was an intersting question.

Maybe it will change in the next version...:)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top