Reputation: 253
Im trying connect to a API and get the data from it. But Im not getting Anything after HttpResponseMessage code line.if (response.IsSuccessStatusCode) never runs. I have tried everything, but nothing yet. please help. This is my code.
using System;
using Newtonsoft;
using System.Net.Http.Headers;
using System.Text;
using System.Net.Http;
using System.Web;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.Xml;
using System.Web.Mvc;
using System.Threading.Tasks;
namespace JKLLAppMobile.API
{
public class JKLLAPI : Controller
{
public async Task<List<JasonData>> MakeRequest()
{
List<JasonData> HanaData = new List<JasonData>();
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
queryString["format"] = "json";
queryString["filter"] = "BDATU eq '20170421' and BWLVS eq '609'";
var uri = "https://jkhapimdev.azure-api.net/api/beta/v2/bound/?" + queryString;
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Authorization = new AuthenticationHeaderValue("Ocp-Apim-Subscription-Key", "{Token-Key}");
HttpResponseMessage response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var responseString = await response.Content.ReadAsStringAsync();
string json_data = JsonConvert.SerializeObject(responseString);
}
return HanaData;
}
}
}
Calling Ajax Method function TotalTestMonthly() {
$.ajax({
url: '../JKLLAPI/MakeRequest',
type: 'POST',
dataType: 'json',
cache: false,
async: false,
data: {},
success: function (data) {
if (data.Success == true) {
}
}
});
}
Upvotes: 0
Views: 3178
Reputation: 38785
Since you have said it "never" runs the IsSuccessStatusCode line, not even for after a timeout, I'd guess that you have a deadlock situation happening.
As I commented above, Stephen Cleary has a really good article which describes the problem. He has also penned an MSDN article.
To summarise (in case the linked articles ever disappear):
someTask.Wait();
Note: According to Stephen's MSDN article, console applications do not have this issue because they use the TaskScheduler. VS' Unit Test task runner does have this issue, which is how I learned of it.
So, what can you do?
If you're running async from a GUI context, e.g. a button click, you should change your button click handler to an async method:
// you can't change void to Task because of the type the delegate expects,
// but this is the correct way to do this.
public async void OnClicked(...)
You can then use the standard await, and the context is handled as you would expect.
In your async methods you can call ConfigureAwait:
await Task.Delay(1000).ConfigureAwait(continueOnCapturedContext: false);
// or, simply:
await Task.Delay(1000).ConfigureAwait(false);
This causes the method to execute the rest of the async method in the Thread Pool context, which averts the deadlock.
If for some reason you can't handle, or wrap, the async method, then you can also use Task.Run
:
// You can also use Task<string>.Run(...), for example
var task = Task.Run(async () => await someAsyncMethod());
task.Wait();
Using Task.Run will execute the async method within the Thread Pool context, and thus avoid the deadlock.
My explanation really doesn't do the topic justice, so I highly recommend reading the articles I linked above. I just wanted to make sure my answer contained some valuable content if the links were to ever disappear :-)
Note The correct way to do async is async all the way down (i.e. from the button click to the deepest async call). Task.Run shouldn't be used within an async method.
I've put together my own quick example to demonstrate these techniques:
// Deadlocks
public void button2_Click(object sender, EventArgs e)
{
var task = GetNews();
task.Wait();
MessageBox.Show(task.Result);
}
// Doesn't deadlock
public async void button3_Click(object sender, EventArgs e)
{
var result = await GetNews();
MessageBox.Show(result);
}
// Doesn't deadlock
public void button4_Click(object sender, EventArgs e)
{
var task = GetNews(false);
task.Wait();
MessageBox.Show(task.Result);
}
// Doesn't deadlock
public void button5_Click(object sender, EventArgs e)
{
var task = Task<string>.Run(async () => await GetNews());
task.Wait();
MessageBox.Show(task.Result);
}
// The boolean option is just so that I don't have to write two example methods :)
// You obviously don't have to pass this as a parameter, and can just directly call ConfigureAwait
public async Task<string> GetNews(bool continueOnCapturedContext = true)
{
await Task.Delay(100).ConfigureAwait(continueOnCapturedContext: continueOnCapturedContext);
return "hello";
}
Upvotes: 3