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);
}
Related
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
In c#, I make get and post requests. This is my code
GET
private async Task<string> GetAsync(string uri, Token token, string accept, string content_type)
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(accept)); // ACCEPT header
bool added = client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "text/xml");
if (token != null) client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(token.token_type, token.access_token);
HttpResponseMessage g = await client.GetAsync(uri);
if (g.IsSuccessStatusCode)
{
return await g.Content.ReadAsStringAsync();
}
else
{
errors.AddError(g.ReasonPhrase, await g.Content.ReadAsStringAsync());
return null;
}
}
POST
private async Task<string> PostAsync(string uri, Token token, string postData, string accept, string content_type)
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(accept)); // ACCEPT header
if (token != null) client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(token.token_type, token.access_token);
var content = new StringContent(postData, Encoding.UTF8, content_type);
HttpResponseMessage g = await client.PostAsync(uri, content);
if (g.IsSuccessStatusCode)
{
return await g.Content.ReadAsStringAsync();
}
else
{
errors.AddError(g.ReasonPhrase, await g.Content.ReadAsStringAsync());
return null;
}
}
But I read that you should reuse the httpclient like this
private static HttpClient client = new HttpClient();
as I make lots of frequent requests. However if I re-use the object, the settings like headers persist and that causes issues. Is there a way I can just reset the settings but keep the object?
Thanks
Don't use the HttpClient's default headers. Set the headers on the request:
var content = new StringContent(postData, Encoding.UTF8, content_type) // CONTENT-TYPE header
content.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(accept)); // ACCEPT header
if (token != null)
content.Headers.Authorization = new AuthenticationHeaderValue(token.token_type, token.access_token);
Then all threads can use the same HttpClient throughout the runtime of the application without issue.
I am trying to retrieve some data from an API, the following is my piece of code that makes the request after authenticating and assigning the completed URL.
public async Task<T> GetAPIData<T>(string url)
{
using (var client = HttpClientSetup())
{
var response = await client.GetAsync(url).ConfigureAwait(false);
var JsonResponse = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return JsonConvert.DeserializeObject<T>(JsonResponse);
}
}
private HttpClient HttpClientSetup()
{
var client = new HttpClient { BaseAddress = new Uri(apiBaseUrl) };
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = authenticationHeader;
return client;
}
I am getting an error on the line with ConfigureAwait(false);
as
"HTTPResponseMessage does not contain a definition for ConfigureAwait"
. Could anyone help me as to what might be going wrong?
I need to set a timeout of 10 seconds to all the Http web request in Wp8.1 app. I dont find a Timeout instead a ContinueTimeout property in the HttpWebRequest class.
A Quick search gave be few alternatives. Using a CancellationToken being one and the other one is using Task. Will some one give me pointers as to how to modify my current code.
This is how I'm creating a request
string uri = MyClass.HTTP_URI + "user/server-timestamps";
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = MyClass.HTTP_GET;
request.Accept = "application/json";
request.Headers[HTTP_AUTHENTICATION_TOKEN] = "token"
request.Headers[API_KEY] = API_KEY_VALUE;
This is how I'm sending the request
try
{
WebResponse responseObject = await Task<WebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, request);
HttpWebResponse response = (HttpWebResponse)responseObject;
statusCode = (int)response.StatusCode;
if (statusCode == 200)
{
var responseStream = responseObject.GetResponseStream();
var sr = new StreamReader(responseStream);
received = await sr.ReadToEndAsync();
//Do stuff
}
}
You can use HttpClient class and CancellationTokenSource. Just modify it.
try
{
CancellationTokenSource cts = new CancellationTokenSource(2000);
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new Windows.Web.Http.Headers.HttpMediaTypeWithQualityHeaderValue(""));
HttpRequestMessage msg = new HttpRequestMessage(new HttpMethod("POST"), new Uri("Url"));
HttpResponseMessage response = await client.SendRequestAsync(msg).AsTask(cts.Token);
}
catch(TaskCanceledException ex)
{
}
You can create an extension method than accepts CancellationToken and use it like this:
var request = (HttpWebRequest)WebRequest.Create(uri);
// ...
try
{
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
{
await request.GetResponseAsyncCancelable(cts.Token);
}
}
catch (OperationCanceledException)
{
// handle cancellation, if desired
}
// ...
public static class HttpWebRequestExt
{
public static async Task<HttpWebResponse> GetResponseAsyncCancelable(
this HttpWebRequest #this,
CancellationToken token)
{
using (token.Register(() => request.Abort(), useSynchronizationContext: false))
{
try
{
// BTW: any reason why not use request.GetResponseAsync,
// rather than FromAsync? It's there in WP 8.1:
// var response = await request.GetResponseAsync();
var response = (HttpWebResponse)await Task<WebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, request);
token.ThrowIfCancellationRequested();
return response;
}
catch (WebException ex)
{
// WebException caused by cancellation?
if (!token.IsCancellationRequested)
throw; // no, just re-throw
// yes, wrap it with OperationCanceledException
throw new OperationCanceledException(ex.Message, ex, token);
}
}
}
}
BTW, is there any reason you're not using GetResponseAsync, which is there in WP 8.1? See the code comments inline.
How to set Timeout property to Windows.Web.Http.HttpClient operation. The code sample I used is below.
public HttpClient httpClient;
public CancellationTokenSource cts;
public void SendRequest(addressUri,postrequestbody)
{
HttpHelper.CreateHttpClient(ref httpClient);
cts = new CancellationTokenSource();
HttpRequestMessage msg =
new HttpRequestMessage(new HttpMethod("POST"),
new Uri(addressUri));
msg.Content = new HttpStringContent(postrequestbody);
msg.Content.Headers.ContentType =
new HttpMediaTypeHeaderValue("application/json");
HttpResponseMessage response =
await httpClient.SendRequestAsync(msg).AsTask();
if (response.StatusCode == HttpStatusCode.Ok)
{
}
}
Use a CancellationToken:
try
{
CancellationTokenSource cts = new CancellationTokenSource(2000); // 2 seconds
HttpClient client = new HttpClient();
HttpResponseMessage response = await
client.SendRequestAsync(request).AsTask(cts.Token);
}
catch (TaskCanceledException ex)
{
// Catch operation aborted ...
}