HttpClient and Exception Handling - c#

HttpClientHandler httpClientHandler = new HttpClientHandler();
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
HttpClient client = new HttpClient(httpClientHandler);
client.BaseAddress = new Uri(url);
try
{
client.Timeout = TimeSpan.FromSeconds(30);
var response = await client.PostAsync(uri, content);
if (response.IsSuccessStatusCode)
{
// do something
}
}
catch (HttpRequestException ex)
{
// do error stuff
}
catch (TaskCanceledException ex)
{
// do error stuff #2
}
catch (Exception ex)
{
// do error stuff #3
}
I am new to HttpClient.
During our test, we shut down the web service that this code is hitting in order to test this block of code. (BTW, it works as expected when the web service is running.)
Why does it take 2 minutes and 10 sec instead of 30 seconds to hit the TaskCanceledException catch?

The default timeout for HttpClient is 100 seconds. The observed 130 seems pretty strange.
If you run the following code inside dotnet fiddle, then you would see it does cancel the request after 2 seconds and will not wait for a response for 5 seconds:
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class Program
{
public static async Task Main()
{
var handler = new HttpClientHandler();
var client = new HttpClient(handler);
client.BaseAddress = new Uri("https://httpstat.us");
client.Timeout = TimeSpan.FromSeconds(2);
try
{
_ = await client.GetAsync("/200?sleep=5000");
}
catch (OperationCanceledException)
{
"Timed out".Dump();
Environment.Exit(-1);
}
"Finished".Dump();
}
}

Related

GetStringAsync from HttpClient doesn't return anything C#

We are trying to get information from an API.
We use the following code to get an answer. It's a Xamarin Project. We are running it on an Android Emulator with internet connection. Android-Version:11.
When it gets to the line:
var result = await client.GetStringAsync(endpoint);
It just stops and doesn't throw an error. Why is this happening?
private async void Button_Clicked(object sender, EventArgs e)
{
var Get = await AsyncGet();
//await GetItemsAsync();
}
public static async Task<string> AsyncGet()
{
HttpClientHandler GetInsecureHandler()
{
HttpClientHandler handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
{
if (cert.Issuer.Equals("CN=localhost"))
return true;
return errors == System.Net.Security.SslPolicyErrors.None;
};
return handler;
}
var client = new HttpClient(GetInsecureHandler());
try
{
var endpoint = new Uri("My Uri");
var result = await client.GetStringAsync(endpoint);
var json = JsonConvert.DeserializeObject<string>(result);
return result;
}
catch (Exception ex)
{
string checkResult = "Error " + ex.ToString();
client.Dispose();
return checkResult;
}
}
Alternative code:
async Task<string> GetItemsAsync()
{
using (HttpClient client = new HttpClient())
{
var response = await client.GetAsync("My Uri");
return await response.Content.ReadAsStringAsync();
}
}
This Code does return the information but only in the console. When it is run with Xamarin, it also doesn't return anything.

Why is this exception happening? (TaskCanceledException )

I'm having a problem with the .NET HttpClient class. Sometimes the snippet below throws a TaskCanceledException, and i can't debug this because is random (I had the bad luck of Apple reject my Xamarin app for that). Can someone explain to me the reason for this exception?
public static HttpResultModel RecoveryPassword(string email)
{
HttpClient httpClient = new HttpClient();
try
{
var url = String.Format(Constants.SERVER_ADDRESS + "/user/forgotPassword/{0}/", email);
var request = new HttpRequestMessage(new HttpMethod("POST"), url)
{
Content = new StringContent(email, Encoding.UTF8, "application/json"),
};
//to be more specific, this line throws the exception
var result = httpClient.SendAsync(request).Result;
string message = result.Content.ReadAsStringAsync().Result;
if (result.IsSuccessStatusCode)
{
var response = JsonConvert.DeserializeObject<HttpResultModel>(message);
response.OperationSuccess = true;
return response;
}
else
{
var response = JsonConvert.DeserializeObject<HttpResultModel>(message);
response.OperationSuccess = false;
return response;
}
}
catch (Exception ex)
{
throw ex;
}
}
}
This is due to either one of the two reasons:
A server disconnection
a timeout by the Http client. The default for HttpClient is 100 seconds.
You can set this to an infinite timespan.
httpClient.Timeout = System.Threading.Timeout.InfiniteTimeSpan;
each request can be then be set to specific timeouts if needed, as the HttpClient
timeout is on a higher level

c# HttpClient MessageHandler random forbidden

I have a program which does API call using HttpClient and overriding DelegatingHandler class to retry request on failure as shown below.
class TestHandler
{
public static void APICallTest()
{
var handler = new HttpClientHandler() { Credentials = CredentialCache.DefaultNetworkCredentials };
var client = new HttpClient(new RetryMessageHandler(handler));
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Clear();
client.Timeout = TimeSpan.FromSeconds(90);
client.DefaultRequestHeaders.Host = "lab.abc.xyz.def.net";
ServicePointManager.ServerCertificateValidationCallback
+= (sender, cert, chain, sslPolicyErrors) => true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls |
SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
for (int i = 0; i < 499; i++)
{
try
{
using (HttpResponseMessage res =
client.GetAsync("https://abc.xyz.def.net/rest/").Result)
{
if (res != null)
{
Console.WriteLine("response: " + res);
}
}
}
catch (Exception ex)
{
throw ex;
}
}
}
}
public class RetryMessageHandler : DelegatingHandler
{
public RetryMessageHandler(HttpMessageHandler innerhandler):base(innerhandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
HttpResponseMessage response = null;
var exceptions = new List<Exception>();
for (int attempt = 0; attempt < 3; attempt++)
{
await Task.Delay(5 * attempt).ConfigureAwait(false);
try
{
response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
catch (System.Net.Http.HttpRequestException ex)
{
exceptions.Add(ex);
}
}
throw new AggregateException(exceptions);
}
}
The program works with successful response from API. In 500 requests 2-3 requests fail with Forbidden 403. The unsuccessful API calls is random. The logs in API server show that the failed request had no Credentials.
Does anyone have idea on the reason for random failure?
How do I check if Credentails is sent in every request?

Receiving TaskCanceledException when making http request

I received System.Threading.Tasks.TaskCanceledException when making Http request.
public async Task<CommonResult<T>> GetRequest<T>(TokenModel token, string url)
{
using (var client = new HttpClient())
{
client.MaxResponseContentBufferSize = int.MaxValue;
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(token.TokenType, token.AccessToken);
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
return await OK<T>(response);
}
else
{
//The response is authorized but some other error.
if (IsAuthorized(response.StatusCode))
return Error<T>(response.StatusCode.ToString());
//Unable to refresh token.
if (!await RenewToken(token))
return Error<T>("Fail to refresh token");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(GlobalData.Token.TokenType, GlobalData.Token.AccessToken);
response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
return await OK<T>(response);
}
else
{
return Error<T>(response.StatusCode.ToString());
}
}
}
}
It happens when I debug the server code and not continue. Is this natural behaviour or am I missing something in the client code?
This is expected behaviour as by default HttpClient sets a timeout of 100 seconds.
HttpClient Timeout
You can adjust on your HttpClient and set a custom timeout duration. For example you can set an InfiniteTimeSpan to prevent timeouts from occuring.
client.Timeout = Timeout.InfiniteTimeSpan;
HttpClient Request Timeout
You can additionally define a timeout per request using a CancellationTokenSource
using (var cts = new CancellationTokenSource(Timeout.InfiniteTimeSpan))
{
await client.GetAsync(url, cts.Token).ConfigureAwait(false);
}

C# HttpClient server timeout cancels all subsequent requests

I have followed the example here and here to handle timeouts successfully with the C# HttpClient but I just can't make it work!
var urls = new List<string> { "/success", "/willtimeout", "/success" };
var baseAddress = "http://endpoint";
var httpClient = new HttpClient();
httpClient.Timeout = new TimeSpan(0, 0, 30);
httpClient.BaseAddress = new Uri(baseAddress);
foreach (var url in urls)
{
try
{
var cs = CancellationTokenSource.CreateLinkedTokenSource(CancellationToken.None);
cs.CancelAfter(new TimeSpan(0, 0, 3));
var result = await httpClient.GetAsync(urls, cs.Token);
Console.WriteLine("Success");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
This code will print
Success
A task was canceled.
A task was canceled.
How can I make this work properly without creating a new HttpClient every time?
CreateLinkedTokenSource Creates a CancellationTokenSource that will be in the canceled state when any of the source tokens are in the canceled state.
So I guess this is the problem, just create new token source every time and don't link it to anything:
try
{
var cs = new CancellationTokenSource();
// ...

Categories

Resources