Borrowing from the Get method in https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client I have written the following. While being new to C# I assumed the await would complete the API call then move on, but what's happening is that line executes then exits the method without running another line of code (the if statement, the return). I've probably assumed other things as well, which has led me to this predicament.
What should the code be to consistently get a response from the API call and deserialize the Json so I can retrieve the 2 bits of data I actually need?
Any other suggested improvements to my code also greatly appreciated.
The method call:
var ReturnedData = GetProductAsync(companyCode);
The method:
//API Call method - https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client
static HttpClient client = new HttpClient();
static async Task<ReturnedAPIdata> GetProductAsync(string CoCode)
{
// TODO - This key will need to be taken out of the code and put in a config file or something
string DavesKey = "abc123";
string path = "http://api.marketstack.com/v1/eod?access_key=" + DavesKey + "&symbols=" + CoCode + ".XASX&sort=DESC&limit=1&offset=0";
ReturnedAPIdata ThatAPIdata = null;
HttpResponseMessage response = await client.GetAsync(path);
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
// If we have an API response, deserialise the Json data... somehow
//ThatAPIdata = await response.Content.ReadAsAsync<ReturnedAPIdata>(); // ReadAsAsync has been deprecated, but not replaced. Handy
string responseBody = await response.Content.ReadAsStringAsync();
// Which one of these fuckers actually works. Use an API, they said. It'll be fun, they said. ARG!
ReturnedAPIdata Arses = System.Text.Json.JsonSerializer.Deserialize<ReturnedAPIdata>(responseBody); // attempt 3
List<ReturnedAPIdata> Cock = JsonConvert.DeserializeObject<List<ReturnedAPIdata>>(responseBody); // attempt 2
ReturnedAPIdata Balls = JsonConvert.DeserializeObject<ReturnedAPIdata>(responseBody); // attempt 1
}
Console.WriteLine("FFFFFFFFFfffff....");
return ThatAPIdata;
}
The Conrole.Writeline at the end is just for a breakpoint so I can assess which deserialise attempt works best, I've yet to see be reached to stop on.
If the following code is run:
static void Main(string[] args)
{
Console.WriteLine("Before calling async method");
GetProductAsync();
Console.WriteLine("After calling async method");
}
static async Task<string> GetProductAsync()
{
await Task.Delay(5000);
Console.WriteLine("Inside async method after await");
return "Got all Products";
}
The following result is printed to console:
Before calling async method
System.Threading.Tasks.Task`1[System.String]
After calling async method
So the execution falls through even though the method GetProductAsync
is defined as async
and there's an await for 5 seconds, also notice that inside of the async method there's a Console.WriteLine("Inside async method after await");
which also doesn't get printed! And the return value doesn't get printed either!
So what's happening here? Just because the method was defined as async and there's an await inside of it won't mean the caller is guaranteed async execution!
Specifically the Main
method calling it doesn't await
the result so that's why it's falling through.
Now if the code is changed and Main is awaiting the GetProductAsync
method:
static async Task Main(string[] args)
{
Console.WriteLine("Before calling async method");
var result = await GetProductAsync();
Console.WriteLine("After calling async method");
Console.WriteLine(result);
}
static async Task<string> GetProductAsync()
{
await Task.Delay(5000);
Console.WriteLine("Inside async method after await");
return "Got all Products";
}
Now the result printed to the console is:
Before calling async method
Inside async method after await
After calling async method
Got all Products
So in this case the result was awaited correctly inside of main, the execution returned to the caller and is now free to continue doing other tasks such as updating the GUI (which isn't the case in this simple console app).
Hopefully this illustrates what's happening here, basically the caller, in this case Main
, also needs to await the result from the async GetProductAsync
method to see the result.
This article does a good job of explaining various pitfalls and gotchas! without going in too deep https://www.pluralsight.com/guides/understand-control-flow-async-await