The Stackoverflow API, if the request is not successful, how to read the response please?
using (HttpClient Client = new HttpClient(handler))
{
string response = string.Empty;
response = Client.GetStringAsync(apiUri.Uri).Result;
return JsonConvert.DeserializeObject<Questions<Question>>(response);
}
When an error occurs:
{"error_id":502,"error_message":"too many requests from this IP, more requests available in 82216 seconds","error_name":"throttle_violation"}
An error InnerException = {"Response status code does not indicate success: 400 (Bad Request)."}
The following paragraph is from Call a Web API From a .NET Client (C#)
HttpClient does not throw an exception when the HTTP response contains an error code. Instead, the IsSuccessStatusCode property is false if the status is an error code. If you prefer to treat HTTP error codes as exceptions, call HttpResponseMessage.EnsureSuccessStatusCode on the response object. EnsureSuccessStatusCode throws an exception if the status code falls outside the range 200–299. Note that HttpClient can throw exceptions for other reasons — for example, if the request times out.
In your case the code could be something like the following.
var response = await client.GetAsync(apiUri.Uri);
if (!response.IsSuccessStatusCode)
{
var text = await response.Content.ReadAsStringAsync();
// Log error
return null; // throw etc.
}
else
{
var text = await response.Content.ReadAsStringAsync();
var o = JsonConvert.DeserializeObject<Questions<Question>>(o);
return o;
}
(You can move var text = ... outside of if if you wish.)
Status code can be examined instead of calling IsSuccessStatusCode, if needed.
if (response.StatusCode != HttpStatusCode.OK) // 200
{
throw new Exception(); / return null et.c
}
Related
I use xamarin forms to create an mobile app for Android and iOS. I need to make Http Request, so I use HttpClient.
Here is a simple code of request :
var client = new HttpClient();
try
{
string requestUrl = URL_DATABASE + "xxx";
var content = new StringContent("{\"param\":\"" + param+ "\"}", Encoding.UTF8, "application/json");
var response = await client.PostAsync(requestUrl, content);
if (response.StatusCode == HttpStatusCode.OK)
{
var result = await response.Content.ReadAsStringAsync();
return result;
}
return "{\"status\":-1}";
}
catch (Exception ex) // Error catched : "the request timed out"
{
return "{\"status\":-1}";
}
I used Postman to check result of my request and work's well, I got good response without timeout.
I noticed that error occurs sometimes but can last an hour.
error : the request timed out
Thank you in advance for your help
The code goes below
public static async Task<string> getForwardUrl(string url)
{
try
{
HttpClient client = new HttpClient();
HttpRequestMessage forwardRequest = new HttpRequestMessage();
forwardRequest.RequestUri = new Uri(url);
HttpResponseMessage Message = await client.SendAsync(forwardRequest);
return Message.RequestMessage.RequestUri.OriginalString;
}
catch (Exception ex)
{
WriteLine(ex.Message);
}
//...
}
When I run this in a uwp project, exception occurs. The message of this exception shows that the redirection request would change the safe connection to an unsafe one(After that , I checked the URL of the login page , It's https ,but the page after I logged in is http).
I find a similar question, he recommends using Windows.Web.Http instead of System.Net.Http but I get the same error message.
Thanks for your reply
EDIT:
The URL is: https://tinyurl.com /57muy (remove the space) or short a http url with tinyurl.com! The problem only occurs with a shortet http side!
Error: An error occurred while sending the request. Innermessage: Error message not found for this error
According to your description, I'd suppose you are developing a UWP app. And as you've mentioned, we got the exception here because the redirection request would change the safe connection to an unsafe one. To solve this problem, we can turn off auto-redirect and do the redirection by ourselves.
For example:
public static async Task<string> getForwardUrl(string url)
{
var handler = new System.Net.Http.HttpClientHandler();
handler.AllowAutoRedirect = false;
var client = new System.Net.Http.HttpClient(handler);
var response = await client.GetAsync(url);
if (response.StatusCode == System.Net.HttpStatusCode.Redirect || response.StatusCode == System.Net.HttpStatusCode.Moved)
{
return response.Headers.Location.AbsoluteUri;
}
return url;
}
I'm building an HTTP API client using RestSharp, and I've noticed that when the server returns an HTTP error code (401 Unauthorized, 404 Not Found, 500 Internal Server Error, etc.) the RestClient.Execute() doesn't throw an exception - instead I get a valid RestResponse with a null .Data property. I don't want to manually check for every possible HTTP error code within my API client - does RestSharp provide a better way of passing these errors to my client application?
A little further detail. RestSharp exposes a Response.ErrorException property - if the RestClient.Execute<T>() call causes any exception, it'll be exposed via the ErrorException property instead of being thrown. Their documentation includes the following example:
// TwilioApi.cs
public class TwilioApi {
const string BaseUrl = "https://api.twilio.com/2008-08-01";
public T Execute<T>(RestRequest request) where T : new()
{
var client = new RestClient();
client.BaseUrl = BaseUrl;
client.Authenticator = new HttpBasicAuthenticator(_accountSid, _secretKey);
request.AddParameter("AccountSid", _accountSid, ParameterType.UrlSegment); // used on every request
var response = client.Execute<T>(request);
if (response.ErrorException != null)
{
const string message = "Error retrieving response. Check inner details for more info.";
var twilioException = new ApplicationException(message, response.ErrorException);
throw twilioException;
}
return response.Data;
}
}
I've adopted that pattern in my code, but my API server is returning a 401 Unauthorized and yet the ErrorException property is still null. I can see the Unauthorized status code and error message in the RestResponse.StatusCode and RestResponse.StatusDescription properties - but I'm confused as to why an unauthorized response wouldn't result in the ErrorException field being populated.
I encountered this same problem while trying to create a generic error handler for a RestSharp WebAPI client. Given these extension methods:
public static class RestSharpExtensionMethods
{
public static bool IsSuccessful(this IRestResponse response)
{
return response.StatusCode.IsSuccessStatusCode()
&& response.ResponseStatus == ResponseStatus.Completed;
}
public static bool IsSuccessStatusCode(this HttpStatusCode responseCode)
{
int numericResponse = (int)responseCode;
return numericResponse >= 200
&& numericResponse <= 399;
}
}
I made a request that required the response to be deserialized:
public async Task<ResponseModel<TResponse>> PerformRequestAsync<TResponse>(IRestRequest request)
{
var response = await _client.ExecuteTaskAsync<ResponseModel<TResponse>>(request);
ResponseModel<TResponse> responseData;
if (response.IsSuccessful())
{
responseData = response.Data;
}
else
{
string resultMessage = HandleErrorResponse<TResponse>(request, response);
responseData = new ResponseModel<TResponse>
{
Success = false,
ResultMessage = resultMessage
};
}
return responseData;
}
However, during testing, I found that when I had no error handling configured for that case, my web serivce returned an HTML-formatted 404 page when an unmapped URL was requested. This caused the response.ErrorException property to contain the following string:
Reference to undeclared entity 'nbsp'. Line n, position m.
As apparently RestSharp tried to parse the response as XML, even though the content-type was text/html. Maybe I'll file an issue with RestSharp for this.
Of course in production you should never get a 404 when calling your own service, but I want this client to be thorough and reusable.
So there's two solutions I can think of:
Inspect the status code and show the description
Make sure the service returns an error object that you can parse
The former is done quite easily. In HandleErrorResponse() I build the result message (user presentable) and error string (loggable) based on the numeric value of the status code:
public string HandleErrorResponse(IRestRequest request, IRestResponse response)
{
string statusString = string.Format("{0} {1} - {2}", (int)response.StatusCode, response.StatusCode, response.StatusDescription);
string errorString = "Response status: " + statusString;
string resultMessage = "";
if (!response.StatusCode.IsScuccessStatusCode())
{
if (string.IsNullOrWhiteSpace(resultMessage))
{
resultMessage = "An error occurred while processing the request: "
+ response.StatusDescription;
}
}
if (response.ErrorException != null)
{
if (string.IsNullOrWhiteSpace(resultMessage))
{
resultMessage = "An exception occurred while processing the request: "
+ response.ErrorException.Message;
}
errorString += ", Exception: " + response.ErrorException;
}
// (other error handling here)
_logger.ErrorFormat("Error response: {0}", errorString);
return resultMessage;
}
Now as my API responses always are wrapped in a ResponseModel<T> of my making, I can set up an exception filter and a NotFound route to return a parsable response model with the error or exception message in the ResultMessage property:
public class HandleErrorAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
// (log context.Exception here)
context.Response = context.Request.CreateResponse(HttpStatusCode.InternalServerError, new ResponseModel<object>
{
Success = false,
ResultMessage = "An exception occurred while processing the request: " + context.Exception.Message
});
}
}
And:
public class ErrorController : ApiController
{
public HttpResponseMessage Handle404()
{
const string notFoundString = "The requested resource could not be found";
var responseMessage = Request.CreateResponse(HttpStatusCode.NotFound, new ResponseModel<object>
{
Success = false,
ResultMessage = notFoundString
});
responseMessage.ReasonPhrase = notFoundString;
return responseMessage;
}
}
This way the response from my service can always be parsed by RestSharp, and I can use the generic logging method:
public string HandleErrorResponse<TResponseModel>(IRestRequest request, IRestResponse<<ResponseModel<TResponseModel>> response)
And log the actual response at // (other error handling here), if available:
if (response.Data != null && !string.IsNullOrWhiteSpace(response.Data.ResultMessage))
{
resultMessage = response.Data.ResultMessage;
errorString += string.Format(", Service response: \"{0}\"", response.Data.ResultMessage);
}
RestSharp has added boolean property IRestResponse.IsSuccessful which covers your use case. I couldn't find any documentation referring to this property, but here's the line that defines the property's method.
Interesting to note is that RestSharp considers codes 200-299 to be successful, while CodeCaster considers codes 200-399 to be successful.
It should be enough to check for a success code, and throw or report the error if you get any other code apart from success. This usually means checking for HTTP Status 200 after every request. If you create a new resource, you should expect Status 201.
With most APIs/frameworks, it is very very unusual to see any other status code except these if nothing has gone wrong.
I have a restful web service. If someone calls a particular method with the wrong key, I return this:
OutgoingWebResponseContext response = WebOperationContext.Current.OutgoingResponse;
response.StatusCode = System.Net.HttpStatusCode.Unauthorized;
response.StatusDescription = "Invalid key provided.";
If I call it using Firefox with Firebug running, send an invalid key and handle the error in my calling code like:
string serviceResponse = "";
try
{
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
string statusCode = response.StatusCode.ToString();
string statusDescription = response.StatusDescription.ToString();
}
}
catch(Exception ex)
{
serviceResponse = ex.Message;
}
the Response headers show:
HTTP:1.1 200 OK
Having handled the error, I can show a message on the screen. However, as soon as the 'using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)' line is hit, an error is thrown and the response object seems to be discarded.
If I don't put the HttpWebResponse code in a try catch block, a 401 unauthorized message shows in the browser but Firebug now shows:
HTTP:1.2 500 Internal Server Error
... which is weird, as I am sending a 401 back.
What is the point, in a Restful web service, of setting the response StatusCode and StatusDescription as, in a browser calling the web service, as soon as a 401 or 500 StatusCode is encountered, an error is thrown and the Response object discarded.
If a 500 or 401 is returned, how are you supposed to read the StatusDescription?
I have a WCF service that is running frequent (1000+) outbound connections per minute to external APIs.
My code throws the following exceptions frequently, but not always showing that is is a WebException with the WebException status property being ReceiveFailure
The code that is making the outbound request is the following:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(paramBuilder.ToString());
request.ServicePoint.ConnectionLeaseTimeout = 0;
request.Method = "GET";
request.Timeout = 33000; //33 Second Timeout Is By Design
Stream stream = default(Stream);
HttpWebResponse response = default(HttpWebResponse);
try
{
response = (HttpWebResponse) request.GetResponse();
stream = response.GetResponseStream();
reader = new StreamReader(stream,Encoding.UTF8);
string str = reader.ReadToEnd();
return str;
}
catch (WebException exception)
{
//Handle WebException
}
catch (Exception exception)
{
//Handle Exception
}
finally
{
if (reader != null)
reader.Dispose();
if (response != null)
response.Close();
if (stream != null)
stream.Dispose();
}
The exception stack trace shows that the exception is caused from GetResponse().
What could be causing this to happen that I receive an occasional WebException -ReceiveFailure.
I have already reference the MSDN documentation for this status, but that doesn't help me.
Shooting in the dark here...
There is a special condition, while waiting for response: if the system clock is being set automatically by the Windows Time service, or manually, you may experience some unpredictable results.
If you're sending your requests over HTTPS, maybe you're facing a regular timeout that was wrongly thrown as a ReceiveFailure.
Check this article for more information: http://support.microsoft.com/kb/2007873
I have a related problem and I realise a few things while I was searching for a solution.
WebExceptionStatus enum is not equivalent to http status code that the API you call returned. Instead it is a enum of possible error that may occour during a http call.
The WebExceptionStatus error code that will be returned when you receive an error (400 to 599) from your API is WebExceptionStatus.ProtocolError aka number 7 as int.
When you need to get the response body or the real http status code returned from the api, first you need to check if WebException.Status is WebExceptionStatus.ProtocolError. Then you can get the real response from WebExceptionStatus.Response and read its content.
Sometimes the timeout is handled by the caller (aka your code) so you do not have a response in that case. So you can look if WebException.Status is WebExceptionStatus.Timeout
This is an example:
try
{
...
}
catch (WebException webException)
{
if (webException.Status == WebExceptionStatus.ProtocolError)
{
var httpResponse = (HttpWebResponse)webException.Response;
var responseText = "";
using (var content = new StreamReader(httpResponse.GetResponseStream()))
{
responseText = content.ReadToEnd(); // Get response body as text
}
int statusCode = (int)httpResponse.StatusCode; // Get the status code
}
else if (webException.Status == WebExceptionStatus.ProtocolError)
{
// Timeout handled by your code. You do not have a response here.
}
// Handle other webException.Status errors. You do not have a response here.
}