'system.threading.tasks.taskcanceledexception a task was canceled exception
My code to fetch a huge set of data from an API is like this
public static async Task<model> GetDataAsyncs(string url)
{
// Initialization.
mymodel responseObj = new mymodel();
using (var httpClientHandler = new HttpClientHandler())
{
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
using (var client = new HttpClient(httpClientHandler))
{
// Setting Base address.
client.BaseAddress = new Uri(apiBasicUri);
// Setting content type.
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Initialization.
HttpResponseMessage response = new HttpResponseMessage();
// HTTP Get
response = await client.GetAsync(url ).ConfigureAwait(false);
// Verification
if (response.IsSuccessStatusCode)
{
// Reading Response.
string result = response.Content.ReadAsStringAsync().Result;
responseObj.Status = true;
responseObj.Data = result;
}
}
}
return responseObj;
}
And I am calling above function like this inside my controller
public ActionResult myActionMethod()
{
string res= helper.GetDataAsync("url").Result.Data;
}
Ocassionally this throws an error system.threading.tasks.taskcanceledexception a task was canceled . This does not occurs every time. Can anyone please point out what I am doing wrong here?
Solution 1:[1]
I can't say for sure why this is happening, but there are some red flags in your code that can be cleaned up and might resolve this.
The first is your use of .ConfigureAwait(false). It can cause some unintended consequences, so I suggest you don't use it. I talk about it more in an article I recently wrote.
Second, use await instead of .Result whenever possible, which is almost always. Using .Result can also cause unintended, hard-to-debug consequences. In your code, I see no reason you can't use await.
Third, the documentation of HttpClient says:
HttpClient is intended to be instantiated once and re-used throughout the life of an application. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. This will result in SocketException errors.
So you can declare a static HttpClient and reuse that every time you need it.
Fourth, there's no need for this line:
HttpResponseMessage response = new HttpResponseMessage();
You're instantiating a new HttpResponseMessage here, but then immediately overwriting it in the next line.
Making those changes, your code could look like this:
private static HttpClient _client = new HttpClient(
new HttpClientHandler {ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; }}
) {
BaseAddress = new Uri(apiBasicUri),
DefaultRequestHeaders = {
Accept = { new MediaTypeWithQualityHeaderValue("application/json") }
}
};
public static async Task<model> GetDataAsyncs(string url)
{
mymodel responseObj = new mymodel();
var response = await _client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
responseObj.Status = true;
responseObj.Data = result;
}
return responseObj;
}
And then change your controller action to be async and use await:
public async Task<ActionResult> myActionMethod()
{
var res = (await helper.GetDataAsync("url")).Data;
}
See if you still end up getting exceptions after making those changes.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Gabriel Luci |
