views:

1814

answers:

4

I'm setting a custom StatusDescription in a RESTful WCF service when an exception is thrown. It's meant to provide the caller with a friendly description of why they got the failure status code.

The following is the response I see in Fiddler. So I know that my custom message is getting pushed back through to the caller. What I can't figure out is how to retrieve that message from .NET. The StatusDescription does not contain this string.

If you could provide a simple bit of sample code that would be great.

HTTP/1.1 500 Message: "Exception of type 'Exceptions.DataSourceNotFoundException' was thrown." Uri: http://www.test1.com/
Content-Length: 0
Server: Microsoft-HTTPAPI/2.0
Date: Mon, 20 Apr 2009 07:13:40 GMT

UPDATE
The answer to this question does not work in Silverlight. Tested in Silverlight 2 and 3 beta.

A: 

Not a .NET programmer, Found this on msdn

catch(WebException ex)
{
    string message = ((HttpWebResponse)ex.Response).StatusDescription;
}
Dipen
@spoon16, care to explain why you've changed this wrong answer and then accepted it as the best answer?
Arjan
+2  A: 

I've not used .NET in many years, but in Java people often expect to get a HTTP code and message for 404 Not Found errors, while 404s actually make Java throw a FileNotFoundException. For those situations, in Java one should use HttpURLConnection#getErrorStream rather than #getResponseMessage.

So: maybe something similar is happening in a .NET client for 500 responses? Indeed the documentation for HttpWebRequest states:

The HttpWebRequest class throws a WebException when errors occur while accessing a resource. The WebException.Status property contains a WebExceptionStatus value that indicates the source of the error. When WebException.Status is WebExceptionStatus.ProtocolError, the Response property contains the HttpWebResponse received from the resource.

Detail: the link to Response above refers to WebException.Response, not to HttpWebRequest.GetResponse. So, WebException has its own Response property. The following example is based on the WebException.Response documentation, but I did not test it.

IMPORTANT: note that this does NOT use GetResponse from HttpWebRequest, but Response from WebException:

try {
  HttpWebRequest myHttpWebRequest = 
      (HttpWebRequest) WebRequest.Create("http://www.example.org/not_found");
  HttpWebResponse myHttpWebResponse =
      (HttpWebResponse) myHttpWebRequest.GetResponse();
  myHttpWebResponse.Close();
}
catch(WebException e) {
  Console.WriteLine("Exception Message: " + e.Message);
  if(e.Status == WebExceptionStatus.ProtocolError) {
    Console.WriteLine("Status Code: {0}",
        ((HttpWebResponse)e.Response).StatusCode);
    Console.WriteLine("Status Description: {0}",
        ((HttpWebResponse)e.Response).StatusDescription);
    }
}
catch(Exception e) {
  Console.WriteLine(e.Message);
}
Arjan
A: 

I think your issue is that your status code is 500. When the status code isn't OK (200 or some type of redirect), WebRequest.GetResponse() call throws a WebException in .NET.

This exception will actually contain the HttpWebResponse object with the StatusDescription set. The samples below are from MSDN:

public static void GetPage(String url) 
    {
        try 
           {    
                // Creates an HttpWebRequest for the specified URL. 
                HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url); 
                // Sends the HttpWebRequest and waits for a response.
                HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse(); 
                if (myHttpWebResponse.StatusCode == HttpStatusCode.OK)
                   Console.WriteLine("\r\nResponse Status Code is OK and StatusDescription is: {0}",
                                        myHttpWebResponse.StatusDescription);
                // Releases the resources of the response.
                myHttpWebResponse.Close(); 

            } 
        catch(WebException e) 
           {
                Console.WriteLine("\r\nWebException Raised. The following error occured : {0}",e.Status); 
           }
        catch(Exception e)
        {
            Console.WriteLine("\nThe following Exception was raised : {0}",e.Message);
        }
    }

Source: http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.statuscode.aspx

To actually get at the status, you'll need to get the HttpWebResponse object from the exception itself:

try {
   // Create a web request for an invalid site. Substitute the "invalid site" strong in the Create call with a invalid name.
     HttpWebRequest myHttpWebRequest = (HttpWebRequest) WebRequest.Create("invalid site");

    // Get the associated response for the above request.
     HttpWebResponse myHttpWebResponse = (HttpWebResponse) myHttpWebRequest.GetResponse();
    myHttpWebResponse.Close();
}
catch(WebException e) {
    Console.WriteLine("This program is expected to throw WebException on successful run."+
                        "\n\nException Message :" + e.Message);
    if(e.Status == WebExceptionStatus.ProtocolError) {
        Console.WriteLine("Status Code : {0}", ((HttpWebResponse)e.Response).StatusCode);
        Console.WriteLine("Status Description : {0}", ((HttpWebResponse)e.Response).StatusDescription);
    }
}
catch(Exception e) {
    Console.WriteLine(e.Message);
}

Source: http://msdn.microsoft.com/en-us/library/system.net.webexception.status.aspx

Sean Turner
Errrr, how is this any different from earlier answers?
Arjan
A: 

I can't tell if it's a copy/paste thing, but the "Uri:" header is on the same line as the status code -- that could be an issue.

Most reason codes are a few words without a ":" and without quotes: http://tools.ietf.org/html/rfc2616#section-6.1.1 So I suspect that the header parser thinks that "Message:" is the start of an HTTP header (check webResponse.Headers["Message"]).

You could add a header (say, X-Error-Details) instead.

JLamb