'WebException how to get whole response with a body?

In WebException I cannot see body of GetResponse. This is my code in C#:

try {                
  return GetResponse(url + "." + ext.ToString(), method, headers, bodyParams);
} catch (WebException ex) {
    switch (ex.Status) {
      case WebExceptionStatus.ConnectFailure:
         throw new ConnectionException();                        
     case WebExceptionStatus.Timeout:
         throw new RequestTimeRanOutException();                     
     case WebExceptionStatus.NameResolutionFailure:
         throw new ConnectionException();                        
     case WebExceptionStatus.ProtocolError:
          if (ex.Message == "The remote server returned an error: (401) unauthorized.") {
              throw new CredentialsOrPortalException();
          }
          throw new ProtocolErrorExecption();                    
     default:
          throw;
    }

I see header but I don't see body. This is output from Wireshark for the request:

POST /api/1.0/authentication.json HTTP/1.1    
Content-Type: application/x-www-form-urlencoded    
Accept: application/json    
Host: nbm21tm1.teamlab.com    
Content-Length: 49    
Connection: Keep-Alive    

userName=XXX&password=YYYHTTP/1.1 500 Server error    
Cache-Control: private, max-age=0    
Content-Length: 106    
Content-Type: application/json; charset=UTF-8    
Server: Microsoft-IIS/7.5    
X-AspNet-Version: 2.0.50727    
X-Powered-By: ASP.NET    
X-Powered-By: ARR/2.5

Date: Mon, 06 Aug 2012 12:49:41 GMT    
Connection: close    

{"count":0,"startIndex":0,"status":1,"statusCode":500,"error":{"message":"Invalid username or password."}}

Is it possible somehow to see the message text in WebException? Thank you.



Solution 1:[1]

var resp = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();

dynamic obj = JsonConvert.DeserializeObject(resp);
var messageFromServer = obj.error.message;

Solution 2:[2]

try {
 WebClient client = new WebClient();
 client.Encoding = Encoding.UTF8;
 string content = client.DownloadString("https://sandiegodata.atlassian.net/wiki/pages/doaddcomment.action?pageId=524365");
 Console.WriteLine(content);
 Console.ReadKey();
} catch (WebException ex) {
 var resp = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();
 Console.WriteLine(resp);
 Console.ReadKey();
}

Solution 3:[3]

This only improves on the existing answers. I have written a method that takes care of the details of throwing/rethrowing with an enhanced message, that includes the response body:

Here's my code (in Client.cs):

/// <summary>
///     Tries to rethrow the WebException with the data from the body included, if possible. 
///     Otherwise just rethrows the original message.
/// </summary>
/// <param name="wex">The web exception.</param>
/// <exception cref="WebException"></exception>
/// <remarks>
///     By default, on protocol errors, the body is not included in web exceptions. 
///     This solutions includes potentially relevant information for resolving the
///     issue.
/// </remarks>
private void ThrowWithBody(WebException wex) {
    if (wex.Status == WebExceptionStatus.ProtocolError) {
        string responseBody;
        try {
            //Get the message body for rethrow with body included
            responseBody = new StreamReader(wex.Response.GetResponseStream()).ReadToEnd();

        } catch (Exception) {
            //In case of failure to get the body just rethrow the original web exception.
            throw wex;
        }

        //include the body in the message
        throw new WebException(wex.Message + $" Response body: '{responseBody}'", wex, wex.Status, wex.Response);
    }

    //In case of non-protocol errors no body is available anyway, so just rethrow the original web exception.
    throw wex;
}

You use it in a catch clause much like the OP showed:

//Execute Request, catch the exception to eventually get the body
try {
    //GetResponse....
    }
} catch (WebException wex) {
    if (wex.Status == WebExceptionStatus.ProtocolError) {
        ThrowWithBody(wex);
    }

    //otherwise rethrow anyway
    throw;
}

Solution 4:[4]

I don't see any answers with using statements, and I don't see any uses of async.

public static class WebExceptionExtensions
{
    public static string GetResponseBody(this WebException webException)
    {
        if (webException.Status == WebExceptionStatus.ProtocolError)
        {
            try
            {
                using (var stream = webException.Response.GetResponseStream())
                {
                    if (stream is null)
                        return string.Empty; // or webException.Message
                    using (var reader = new StreamReader(stream))
                    {
                        string msg = reader.ReadToEnd();
                        if (string.IsNullOrEmpty(msg) && webException.Response is HttpWebResponse response)
                            msg = $"{response.StatusDescription} ({(int)response.StatusCode})"; // provide some error message if not found

                        return msg;
                    }
                }
            }
            catch (WebException) // we tried
            {
                return string.Empty; // or webException.Message
            }
        }
        else
        {
            return string.Empty; // or webException.Message
        }
    }

    public static async Task<string> GetResponseBodyAsync(this WebException webException)
    {
        if (webException.Status == WebExceptionStatus.ProtocolError)
        {
            try
            {
                using (var stream = webException.Response.GetResponseStream())
                {
                    if (stream is null)
                        return string.Empty; // or webException.Message
                    using (var reader = new StreamReader(stream))
                    {
                        string msg = await reader.ReadToEndAsync();
                        if (string.IsNullOrEmpty(msg) && webException.Response is HttpWebResponse response)
                            msg = $"{response.StatusDescription} ((int){response.StatusCode})"; // provide some error message if not found

                        return msg;
                    }
                }
            }
            catch (WebException) //  we tried
            {
                return string.Empty; // or webException.Message
            }
        }
        else
        {
            return string.Empty; // or webException.Message
        }
    }
}

Now, whenever we catch WebExceptions, it is very easy to get the response body.

try 
{
    // Do work here...
}
catch (WebException we)
{
    Console.WriteLine(we.GetResponseBody()); // synchronous
    Console.WriteLine(await we.GetResponseBodyAsync()); // or asynchronous
}
catch (Exception e)
{
    throw new Exception("Unexpected error occured", e);
}

Be Warned, if you attempt to call this method twice, you will get an exception that the stream was already disposed of. This extension method is really only good for showing an error quickly and moving on. If you need extended logic, you'll likely want to make your own method.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 4b0
Solution 3 Marcel
Solution 4