WebClient - get response body on error status code - c#

I'm looking essentially for the same thing asked here:
Any way to access response body using WebClient when the server returns an error?
But no answers have been provided so far.
The server returns a "400 bad request" status, but with a detailed error explanation as response body.
Any ideas on accessing that data with .NET WebClient? It just throws an exception when server returns an error status code.

You cant get it from the webclient however on your WebException you can access the Response Object cast that into a HttpWebResponse object and you will be able to access the entire response object.
Please see the WebException class definition for more information.
Below is an example from MSDN (added reading the content of the web response for clarity)
using System;
using System.IO;
using System.Net;
public class Program
{
public static void Main()
{
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 URL");
// 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);
using (StreamReader r = new StreamReader(((HttpWebResponse)e.Response).GetResponseStream()))
{
Console.WriteLine("Content: {0}", r.ReadToEnd());
}
}
}
catch(Exception e) {
Console.WriteLine(e.Message);
}
}
}

You can retrieve the response content like this:
using (WebClient client = new WebClient())
{
try
{
string data = client.DownloadString(
"http://your-url.com");
// successful...
}
catch (WebException ex)
{
// failed...
using (StreamReader r = new StreamReader(
ex.Response.GetResponseStream()))
{
string responseContent = r.ReadToEnd();
// ... do whatever ...
}
}
}
Tested: on .Net 4.5.2

Related

C# Unable to view Errors on API Response just throws an Exception to Try/Catch

I am writing a program to check check if a Voucher number is Valid and I am finding it difficult to extract the Error Message from a REST API which I am working with.
C# is pretty new to me as normally VB.net but covering for someone at the moment.
Basically I have a HttpWebReqest and HttpWebResponse objects and using the below code I am making a successful request and getting a response just fine.
When everything goes well there are no problems, but for example if a voucher was invalid or the site was invalid I should get a response saying this, as I do in Postman, see below for example.
{
"message": "The given data was invalid.",
"errors": {
"voucher_no": [
"Sorry, that voucher number is invalid."
]
}
}
Instead I get thrown to the Try/Catch.. with the Exception
Error Message Error 422 unprocessable entity,
with no further details or object to check for the real message above?
try
{
using (HttpWebResponse response = mywebrequest.GetResponse() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
{
// I am unable to get to this part of the Code to process the Error because Try/Catch is executed instead ...
}
else
{
Stream dataStream1 = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream1);
responseFromServer = reader.ReadToEnd();
}
}
}
catch (WebException ex)
{
msgbox = new MsgBox_UI("Error", "Web Server Returned an Error", "There is a problem with this Voucher. It may be Expired or invalid at this time.", 1, false, 28);
msgbox.ShowDialog();
break;
}
If any one out there has any ideas as to how I can get this working it would be a great help.
This is by design, GetResponse will throw a WebException (1) when the request returns an 'unsuccessful' status code.
You can check the Status property on the WebException to get the statuscode
and the Response property for the response of the webserver.
The first thing it's better to use HttpClient class instead.
this code should work for you (if not let me know) :
private async Task<string> GetExtensionToken()
{
string url = "https://YourApi.com";
try
{
var httpclient = new HttpClient();
using (HttpResponseMessage response = httpclient.GetAsync(url).Result)
{
using (HttpContent content = response.Content)
{
string result = content.ReadAsStringAsync().Result;
string Is_Not_Valid = "invalid";
if (result.Contains(Is_Not_Valid))
{
string token = "Whatever you want to extract if error page" ;
return token;
}
else
{
string token = "Whatever you want to extract if succeeded" ; return token;
}
}
}
}
catch (Exception ex)
{
return "Error from catch ";
}
}
Usage:
private async void button1_Click(object sender, EventArgs e)
{
richTextBox1.Text = await GetExtensionToken();
}
Ok so I took the advice of Peter above and decided to use HttpClient().
However I actually went with Restharp and installed the Nuget Package RestSharp into my Project. (Main reason is POSTMAN Code Snippet gave me the exact code to use.
Then it worked like a dream.
I am not doing it Async so here is what I found fixed my problem after adding
using RestSharp;
var client = new RestClient("https://api.voucherURL.uk/redeem");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Smart-Auth", "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxx");
request.AddHeader("Accept", "application/json");
request.AddParameter("application/json", "{\n \"voucher_no\":\"JY584111E3\",\n \"site_id\": 14\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);

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.

C# Rest Exception Handling [duplicate]

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]

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]

How to handle errors with HttpWebRequest in WP7?

When using the WebClient class you can check for errors and empty results by using
e.error != null
and
e.result == null
respectively. How would I handle this using the HttpWebRequest class? All examples seem to omit this yet its vital in applications.
The HttpWebRequest uses the IAsyncResult and Begin/End pairs for an operation.
You will have passed a Callback method delegate to Begin operation and then in that callback you call the End method for that operation. To catch an error that may have occured in the asynchronous part of the operation you place a try block around your call to the End method.
For example when calling BeginGetResponse you might pass this call back:-
private void Callback(IAsyncResult asyncResult)
{
try
{
HttpWebResponse resp = (HttpWebResponse)myRequest.EndGetResponse(asyncResult);
}
catch (Exception e)
{
//Something bad happened during the request
}
}
Try a REST client Framework like Spring.Rest ("Spring.Rest" on NuGet), it will do all this boilerplate code for you :
RestTemplate client = new RestTemplate("http://exemple.com/");
client.GetForObjectAsync<string>("path/", r =>
{
if (r.Error != null)
{
}
});
You can use try-catch for that.
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);
}
http://msdn.microsoft.com/en-us/library/system.net.webexception.status.aspx

Categories

Resources