views:

619

answers:

2

I am looking for advice as to how to handle any exceptions thrown in the following code example:

private string SendRequest()
{
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(myURL);
        // Code initialising HttpWebRequest
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        Stream rcvdStream = response.GetResponseStream();
        StreamReader readStream = new StreamReader(rcvdStream, Encoding.UTF8);
        string responseString = readStream.ReadToEnd();
        response.Close();
        readStream.Close();
        return responseString;
}

My main concern is to ensure the StreamReader and HttpRequest object are closed whent the method ends. Should I:

  1. Wrap the lot up in a try/catch/finally logging any exceptions in the catch block and closing the stream in the finally block?
  2. Use a using statement on the HttpWebRequest object instantiation and a nested using statement when creating the StreamReader?
  3. Not worry about it and assume GC will clear everything up when the objects go out of scope as the method is exited?

EDIT: Further investigation has revealed that option 2 can be done without nesting the using statements:

    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    using (Stream rcvdStream = response.GetResponseStream())
    {
        StreamReader readStream = new StreamReader(rcvdStream, Encoding.UTF8);
        payResponse = readStream.ReadToEnd();
    }

This produces the following IL code which demonstrates that it is effectively creating a nested try/finally block:

  IL_00b0:  callvirt   instance class [System]System.Net.WebResponse [System]System.Net.WebRequest::GetResponse()
  IL_00b5:  castclass  [System]System.Net.HttpWebResponse
  IL_00ba:  stloc.s    response
  .try
  {
    IL_00bc:  ldloc.s    response
    IL_00be:  callvirt   instance class [mscorlib]System.IO.Stream [System]System.Net.WebResponse::GetResponseStream()
    IL_00c3:  stloc.s    rcvdStream
    .try
    {
      IL_00c5:  nop
      IL_00c6:  ldloc.s    rcvdStream
      IL_00c8:  call       class [mscorlib]System.Text.Encoding [mscorlib]System.Text.Encoding::get_UTF8()
      IL_00cd:  newobj     instance void [mscorlib]System.IO.StreamReader::.ctor(class [mscorlib]System.IO.Stream,
                                                                                 class [mscorlib]System.Text.Encoding)
      IL_00d2:  stloc.s    readStream
      IL_00d4:  ldloc.s    readStream
      IL_00d6:  callvirt   instance string [mscorlib]System.IO.TextReader::ReadToEnd()
      IL_00db:  stloc.3
      IL_00dc:  nop
      IL_00dd:  leave.s    IL_00f3
    }  // end .try
    finally
    {
      IL_00df:  ldloc.s    rcvdStream
      IL_00e1:  ldnull
      IL_00e2:  ceq
      IL_00e4:  stloc.s    CS$4$0001
      IL_00e6:  ldloc.s    CS$4$0001
      IL_00e8:  brtrue.s   IL_00f2
      IL_00ea:  ldloc.s    rcvdStream
      IL_00ec:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
      IL_00f1:  nop
      IL_00f2:  endfinally
    }  // end handler
    IL_00f3:  nop
    IL_00f4:  leave.s    IL_010a
  }  // end .try
  finally
  {
    IL_00f6:  ldloc.s    response
    IL_00f8:  ldnull
    IL_00f9:  ceq
    IL_00fb:  stloc.s    CS$4$0001
    IL_00fd:  ldloc.s    CS$4$0001
    IL_00ff:  brtrue.s   IL_0109
    IL_0101:  ldloc.s    response
    IL_0103:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_0108:  nop
    IL_0109:  endfinally
  }  // end handler
+2  A: 

Options one and two are your best bets. Option 3 IS NOT a good idea.

I am personally quite fond of the Using statement route. However, the try/catch/finally route is essentially the same, and provides you your needed logging mechanism.

Mitchel Sellers
A: 

How do I handle exceptions in the nested using approach?

Thanks Anand

Anand
@Anand - Stackoverflow is not really a forum (take a quick look at the FAQ) but to answer your question the exception will flow out of the using block so you would need to surround the using block in a try catch block.
Andy Rose
Thanks, Andy. I looked at the FAQ, I dont understand fully what you would have me do differently - I have posted a question that is relevant to the topic. Did you mean, perhaps, that I should start a new thread for such a question? Thanks, Anand
Anand