C# Rest Exception Handling [duplicate] - c#

I am initiating an HttpWebRequest and then retrieving it's response. Occasionally, I get a 500 (or at least 5##) error, but no description. I have control over both endpoints and would like the receiving end to get a little bit more information. For example, I would like to pass the exception message from server to client. Is this possible using HttpWebRequest and HttpWebResponse?
Code:
try
{
HttpWebRequest webRequest = HttpWebRequest.Create(URL) as HttpWebRequest;
webRequest.Method = WebRequestMethods.Http.Get;
webRequest.Credentials = new NetworkCredential(Username, Password);
webRequest.ContentType = "application/x-www-form-urlencoded";
using(HttpWebResponse response = webRequest.GetResponse() as HttpWebResponse)
{
if(response.StatusCode == HttpStatusCode.OK)
{
// Do stuff with response.GetResponseStream();
}
}
}
catch(Exception ex)
{
ShowError(ex);
// if the server returns a 500 error than the webRequest.GetResponse() method
// throws an exception and all I get is "The remote server returned an error: (500)."
}
Any help with this would be much appreciated.

Is this possible using HttpWebRequest and HttpWebResponse?
You could have your web server simply catch and write the exception text into the body of the response, then set status code to 500. Now the client would throw an exception when it encounters a 500 error but you could read the response stream and fetch the message of the exception.
So you could catch a WebException which is what will be thrown if a non 200 status code is returned from the server and read its body:
catch (WebException ex)
{
using (var stream = ex.Response.GetResponseStream())
using (var reader = new StreamReader(stream))
{
Console.WriteLine(reader.ReadToEnd());
}
}
catch (Exception ex)
{
// Something more serious happened
// like for example you don't have network access
// we cannot talk about a server exception here as
// the server probably was never reached
}

I came across this question when trying to check if a file existed on an FTP site or not. If the file doesn't exist there will be an error when trying to check its timestamp. But I want to make sure the error is not something else, by checking its type.
The Response property on WebException will be of type FtpWebResponse on which you can check its StatusCode property to see which FTP error you have.
Here's the code I ended up with:
public static bool FileExists(string host, string username, string password, string filename)
{
// create FTP request
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://" + host + "/" + filename);
request.Credentials = new NetworkCredential(username, password);
// we want to get date stamp - to see if the file exists
request.Method = WebRequestMethods.Ftp.GetDateTimestamp;
try
{
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
var lastModified = response.LastModified;
// if we get the last modified date then the file exists
return true;
}
catch (WebException ex)
{
var ftpResponse = (FtpWebResponse)ex.Response;
// if the status code is 'file unavailable' then the file doesn't exist
// may be different depending upon FTP server software
if (ftpResponse.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
{
return false;
}
// some other error - like maybe internet is down
throw;
}
}

I faced a similar situation:
I was trying to read raw response in case of an HTTP error consuming a SOAP service, using BasicHTTPBinding.
However, when reading the response using GetResponseStream(), got the error:
Stream not readable
So, this code worked for me:
try
{
response = basicHTTPBindingClient.CallOperation(request);
}
catch (ProtocolException exception)
{
var webException = exception.InnerException as WebException;
var rawResponse = string.Empty;
var alreadyClosedStream = webException.Response.GetResponseStream() as MemoryStream;
using (var brandNewStream = new MemoryStream(alreadyClosedStream.ToArray()))
using (var reader = new StreamReader(brandNewStream))
rawResponse = reader.ReadToEnd();
}

You can also use this library which wraps HttpWebRequest and Response into simple methods that return objects based on the results. It uses some of the techniques described in these answers and has plenty of code inspired by answers from this and similar threads. It automatically catches any exceptions, seeks to abstract as much boiler plate code needed to make these web requests as possible, and automatically deserializes the response object.
An example of what your code would look like using this wrapper is as simple as
var response = httpClient.Get<SomeResponseObject>(request);
if(response.StatusCode == HttpStatusCode.OK)
{
//do something with the response
console.Writeline(response.Body.Id); //where the body param matches the object you pass in as an anonymous type.
}else {
//do something with the error
console.Writelint(string.Format("{0}: {1}", response.StatusCode.ToString(), response.ErrorMessage);
}
Full disclosure
This library is a free open source wrapper library, and I am the author of said library. I make no money off of this but have found it immensely useful over the years and am sure anyone who is still using the HttpWebRequest / HttpWebResponse classes will too.
It is not a silver bullet but supports get, post, delete with both async and non-async for get and post as well as JSON or XML requests and responses. It is being actively maintained as of 6/21/2020

Sometimes ex.Response also throws NullReferenceException so below is the best way to handle
catch (WebException ex)
{
using (var stream = ex?.Response?.GetResponseStream())
if(stream != null)
using (var reader = new StreamReader(stream))
{
Console.WriteLine(reader.ReadToEnd());
}
// todo...
}
catch (Exception ex)
{
// todo...
}

**Answer Updated on 14-03-2022**
HttpWebRequest myHttprequest = null;
HttpWebResponse myHttpresponse = null;
try
{
myHttpRequest = (HttpWebRequest)WebRequest.Create(URL);
myHttpRequest.Method = "POST";
myHttpRequest.ContentType = "application/x-www-form-urlencoded";
myHttpRequest.ContentLength = urinfo.Length;
StreamWriter writer = new StreamWriter(myHttprequest.GetRequestStream());
writer.Write(urinfo);
writer.Close();
myHttpresponse = (HttpWebResponse)myHttpRequest.GetResponse();
if (myHttpresponse.StatusCode == HttpStatusCode.OK)
{
//Success code flow
}
myHttpresponse.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);
}
**Updated Answer with try catch block**
[docs.microsoft][1]

Related

Catch External API Error Message as in Postman Body

I am using the following code to complete an External API call.
WebResponse response = request.GetResponse();
string JSONResult = null;
var data = response.GetResponseStream();
using (var reader = new StreamReader(data))
{
JSONResult = reader.ReadToEnd();
}
When there is an exception on the external API, the request.GetResponse throws an error. However, I cannot get the message that is displayed, e.g.
{
"Message": "No HTTP resource was found that matches the request URI '<site>/Foo'.",
"MessageDetail": "No type was found that matches the controller named 'Foo'."
}
Whilst this is displayed in Fiddler and Postman, I cannot get this message anywhere when it is thrown as an exception.
How do I get this specific details when an error on an external API's call is made?
You need to catch the exception and then read the response stream of the exception. Reading the exception's response stream is the same as reading the response of the request. Here is how:
WebRequest request =
WebRequest.Create("http://...");
WebResponse response = null;
try
{
response = request.GetResponse();
}
catch (WebException webEx)
{
if (webEx.Response != null)
{
using (var errorResponse = (HttpWebResponse)webEx.Response)
{
using (var reader = new StreamReader(errorResponse.GetResponseStream()))
{
string error = reader.ReadToEnd();
// TODO: use JSON.net to parse this string
}
}
}
}
Do not put all your code inside the above try block because you are only try(ing) and catch(ing) the request.GetResponse(). The rest of your code needs to go outside that try catch block so you can catch the exceptions from that code separately.

Reading the response stream of a WebException

I have the following method which is basically authenticating users with their Facebook credentials. For some reason, I am getting a WebException when trying to process the authorization key (code). So I tried to read the response stream in order to know what is going on but I keep getting errors while reading the stream. Here's my code:
private void OnAuthCallback(HttpContextWrapper context, WebServerClient client)
{
try
{
IAuthorizationState authorizationState = client.ProcessUserAuthorization(context.Request);
AccessToken accessToken = AccessTokenSerializer.Deserialize(authorizationState.AccessToken);
String username = accessToken.User;
context.Items[USERNAME] = username;
}
catch (ProtocolException e)
{
if (e.InnerException != null)
{
String message = e.InnerException.Message;
if (e.InnerException is WebException)
{
WebException exception = (WebException)e.InnerException;
var responseStream = exception.Response.GetResponseStream();
responseStream.Seek(0, SeekOrigin.Begin);
using (StreamReader sr = new StreamReader(responseStream))
{
message = sr.ReadToEnd();
}
}
EventLog.WriteEntry("OAuth Client", message);
}
}
}
If I remove the responseStream.Seek(0, SeekOrigin.Begin); line, it gives me an ArgumentException with a message that says the stream was not readable. And with this line in place, it tells me that I cannot manipulate a stream that was already closed. How was this stream closed? And why can't I read from it?
You can read the body of the response. I've found the solution in this answer.
You should cast the stream to MemoryStream and use ToArray method, then use Encoding.UTF8.GetString to get text.
private void OnAuthCallback(HttpContextWrapper context, WebServerClient client)
{
try
{
IAuthorizationState authorizationState = client.ProcessUserAuthorization(context.Request);
AccessToken accessToken = AccessTokenSerializer.Deserialize(authorizationState.AccessToken);
String username = accessToken.User;
context.Items[USERNAME] = username;
}
catch (ProtocolException e)
{
if (e.InnerException != null)
{
String message = e.InnerException.Message;
if (e.InnerException is WebException)
{
WebException exception = (WebException)e.InnerException;
message = ExtractResponseString(webException);
}
EventLog.WriteEntry("OAuth Client", message);
}
}
}
public static string ExtractResponseString(WebException webException)
{
if (webException == null || webException.Response == null)
return null;
var responseStream =
webException.Response.GetResponseStream() as MemoryStream;
if (responseStream == null)
return null;
var responseBytes = responseStream.ToArray();
var responseString = Encoding.UTF8.GetString(responseBytes);
return responseString;
}
It looks like you are using DotNetOpenAuth. Unfortunately I think this library closes the response stream of the WebException before wrapping it in the ProtocolException that your code receives. You can enable logging at the DEBUG level to have the response dumped to a log file, but I don't think you'll find any way to access it from your code.
One of the DotNetOpenAuth devs describes the situation here:
DotNetOpenAuth closes the HTTP response stream while handling and throwing the wrapped exception because if DNOA didn't close the stream, your open streams allotment would fill up and then your app would start hanging. DNOA does write the response stream's content to its log if I recall correctly.
Things may have changed in the latest (unreleased) version of DNOA (5.0), as the part of the code that is causing the problem in the current release version has been removed.
a WebException can have different causes and the server isn't always required to return a body under certain (error-)circumstance thus no response.stream.
Have a look at the returned status-code first
Another tool to help you investigate what's going is Fiddler

HttpWebRequest doesn't throw exception

I have a problem with httpwebrequest exception. I use the following code to make a request and catch the exception.
try
{
Uri url= new Uri("https://www.example.com");
HttpWebRequest request2 =(HttpWebRequest)WebRequest.Create(url);
request2.Timeout = 10000;
HttpWebResponse response2 = (HttpWebResponse)request2.GetResponse();
response2.Close();
}
catch (TimeoutException)
{
listBox.Items.Insert(0, "Timeout");
}
catch (WebException ex)
{
using (WebResponse response = ex.Response)
{
HttpWebResponse httpResponse = (HttpWebResponse)response;
listBox.Items.Insert(0, "Status code(Benchmark):" + httpResponse.StatusCode);
}
}
catch
{
listBox.Items.Insert(0, "Failure");
}
At company network when I enter a non-existing url such as www.oiuahsdupiasduiuhid.com; it throws webexception . I got status code: not found or service unavailable. However If I try it at home, it doesn't throw any exception. It waits around 1 second and then without any error stops working. I delete all exceptions to see what is happening but the problem is it doesn’t show any error.
Do you have any idea about what is the problem?
Or any recommendation, how can I handle this problem with a different way?
Without knowing more about your application design, specifically exception handling further up the call stack, it is hard to say why it is behaving like it is when you are at home.
But when I just tried your exact code, it did throw a WebException, however httpResponse.StatusCode throws a NullReferenceException because httpResponse is null. If you are potentially swallowing this exception further up the call stack, it could explain the situation you are seeing.
httpResponse is going to be null in many WebException cases because your request did not receive any response, specifically in the timeout scenario.
Before casting WebException.Response, you need to check the WebException.Status property. If that status suggests a response was received, then you can go check WebException.Response, otherwise it is just going to be null. Try something like:
if(e.Status == WebExceptionStatus.ProtocolError) {
listBox.Items.Insert("Status Code : {0}",
((HttpWebResponse)e.Response).StatusCode);
}
else
{
listBox.Items.Insert("Status : {0}", ex.Status);
}
As a side note, your response2.Close(); is never going to be called when HttpWebResponse response2 = (HttpWebResponse)request2.GetResponse(); throws an exception, so you should be wrapping it in a using block:
using(HttpWebResponse response2 = (HttpWebResponse)request2.GetResponse())
{
// do something with response
}
Thanks to psubsee2003. I got my answer. here is my code which is working properly. I added following codes to webexception.
if (ex.Status == WebExceptionStatus.ProtocolError)
{
using (WebResponse response = ex.Response)
{
HttpWebResponse httpResponse = (HttpWebResponse)response;
listBox2.Items.Insert(0, "Status:" + httpResponse.StatusCode);
}
}
else
{
listBox2.Items.Insert(0, "Status: " + ex.Status);
}

WEbResponse throws 500 Internal server error

I have many times successfully implemented reading data from web pages using technique like this:
WebRequest req = (WebRequest)WebRequest.Create(path);
WebResponse resp = (WebResponse)req.GetResponse(); etc.
.........
However, this time the WebResponse throws an internal error. Otherwise, I can browse the parameter path.
What could be the reason?
I think it could be any number of reasons.
You should try to catch the error and see if you can get any further details from the response. Perhaps try adding the code below and see if that provides any further details:
catch (WebException webex)
{
Console.WriteLine("Unable to perform command: " + req);
String data = String.Empty;
if (webex.Response != null)
{
StreamReader r = new StreamReader(webex.Response.GetResponseStream());
data = r.ReadToEnd();
r.Close();
}
Console.WriteLine(webex.Message);
Console.WriteLine(data);
Probably its not creating the request, WebRequest.Create,
there can be a proxy issue if you are behind any proxy, i got the same problem that my code was unable to connect to any path but it was browsing fine.

How to get error information when HttpWebRequest.GetResponse() fails

I am initiating an HttpWebRequest and then retrieving it's response. Occasionally, I get a 500 (or at least 5##) error, but no description. I have control over both endpoints and would like the receiving end to get a little bit more information. For example, I would like to pass the exception message from server to client. Is this possible using HttpWebRequest and HttpWebResponse?
Code:
try
{
HttpWebRequest webRequest = HttpWebRequest.Create(URL) as HttpWebRequest;
webRequest.Method = WebRequestMethods.Http.Get;
webRequest.Credentials = new NetworkCredential(Username, Password);
webRequest.ContentType = "application/x-www-form-urlencoded";
using(HttpWebResponse response = webRequest.GetResponse() as HttpWebResponse)
{
if(response.StatusCode == HttpStatusCode.OK)
{
// Do stuff with response.GetResponseStream();
}
}
}
catch(Exception ex)
{
ShowError(ex);
// if the server returns a 500 error than the webRequest.GetResponse() method
// throws an exception and all I get is "The remote server returned an error: (500)."
}
Any help with this would be much appreciated.
Is this possible using HttpWebRequest and HttpWebResponse?
You could have your web server simply catch and write the exception text into the body of the response, then set status code to 500. Now the client would throw an exception when it encounters a 500 error but you could read the response stream and fetch the message of the exception.
So you could catch a WebException which is what will be thrown if a non 200 status code is returned from the server and read its body:
catch (WebException ex)
{
using (var stream = ex.Response.GetResponseStream())
using (var reader = new StreamReader(stream))
{
Console.WriteLine(reader.ReadToEnd());
}
}
catch (Exception ex)
{
// Something more serious happened
// like for example you don't have network access
// we cannot talk about a server exception here as
// the server probably was never reached
}
I came across this question when trying to check if a file existed on an FTP site or not. If the file doesn't exist there will be an error when trying to check its timestamp. But I want to make sure the error is not something else, by checking its type.
The Response property on WebException will be of type FtpWebResponse on which you can check its StatusCode property to see which FTP error you have.
Here's the code I ended up with:
public static bool FileExists(string host, string username, string password, string filename)
{
// create FTP request
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://" + host + "/" + filename);
request.Credentials = new NetworkCredential(username, password);
// we want to get date stamp - to see if the file exists
request.Method = WebRequestMethods.Ftp.GetDateTimestamp;
try
{
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
var lastModified = response.LastModified;
// if we get the last modified date then the file exists
return true;
}
catch (WebException ex)
{
var ftpResponse = (FtpWebResponse)ex.Response;
// if the status code is 'file unavailable' then the file doesn't exist
// may be different depending upon FTP server software
if (ftpResponse.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
{
return false;
}
// some other error - like maybe internet is down
throw;
}
}
I faced a similar situation:
I was trying to read raw response in case of an HTTP error consuming a SOAP service, using BasicHTTPBinding.
However, when reading the response using GetResponseStream(), got the error:
Stream not readable
So, this code worked for me:
try
{
response = basicHTTPBindingClient.CallOperation(request);
}
catch (ProtocolException exception)
{
var webException = exception.InnerException as WebException;
var rawResponse = string.Empty;
var alreadyClosedStream = webException.Response.GetResponseStream() as MemoryStream;
using (var brandNewStream = new MemoryStream(alreadyClosedStream.ToArray()))
using (var reader = new StreamReader(brandNewStream))
rawResponse = reader.ReadToEnd();
}
You can also use this library which wraps HttpWebRequest and Response into simple methods that return objects based on the results. It uses some of the techniques described in these answers and has plenty of code inspired by answers from this and similar threads. It automatically catches any exceptions, seeks to abstract as much boiler plate code needed to make these web requests as possible, and automatically deserializes the response object.
An example of what your code would look like using this wrapper is as simple as
var response = httpClient.Get<SomeResponseObject>(request);
if(response.StatusCode == HttpStatusCode.OK)
{
//do something with the response
console.Writeline(response.Body.Id); //where the body param matches the object you pass in as an anonymous type.
}else {
//do something with the error
console.Writelint(string.Format("{0}: {1}", response.StatusCode.ToString(), response.ErrorMessage);
}
Full disclosure
This library is a free open source wrapper library, and I am the author of said library. I make no money off of this but have found it immensely useful over the years and am sure anyone who is still using the HttpWebRequest / HttpWebResponse classes will too.
It is not a silver bullet but supports get, post, delete with both async and non-async for get and post as well as JSON or XML requests and responses. It is being actively maintained as of 6/21/2020
Sometimes ex.Response also throws NullReferenceException so below is the best way to handle
catch (WebException ex)
{
using (var stream = ex?.Response?.GetResponseStream())
if(stream != null)
using (var reader = new StreamReader(stream))
{
Console.WriteLine(reader.ReadToEnd());
}
// todo...
}
catch (Exception ex)
{
// todo...
}
**Answer Updated on 14-03-2022**
HttpWebRequest myHttprequest = null;
HttpWebResponse myHttpresponse = null;
try
{
myHttpRequest = (HttpWebRequest)WebRequest.Create(URL);
myHttpRequest.Method = "POST";
myHttpRequest.ContentType = "application/x-www-form-urlencoded";
myHttpRequest.ContentLength = urinfo.Length;
StreamWriter writer = new StreamWriter(myHttprequest.GetRequestStream());
writer.Write(urinfo);
writer.Close();
myHttpresponse = (HttpWebResponse)myHttpRequest.GetResponse();
if (myHttpresponse.StatusCode == HttpStatusCode.OK)
{
//Success code flow
}
myHttpresponse.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);
}
**Updated Answer with try catch block**
[docs.microsoft][1]

Categories

Resources