退出具有await GetAsync API调用的方法,而不返回结果或运行该方法中的所有代码

问题描述

借用https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client中的Get方法,我写了以下内容。在C#刚接触时,我假设等待将完成API调用然后继续,但是发生的是该行执行然后退出方法,而没有运行另一行代码(if语句,返回)。我可能还假设了其他事情,这使我陷入了这种困境。

代码应该是什么,以便始终如一地从API调用中获得响应并反序列化Json,以便我可以检索实际需要的2位数据?

我对代码的任何其他建议改进也表示赞赏。

方法调用var ReturnedData = GetProductAsync(companyCode);

方法

//API Call method - https://docs.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;
}

最后的Conrole.Writeline只是一个断点,因此我可以评估哪种反序列化方法最有效,但我还没有看到可以继续下去。

解决方法

如果运行以下代码:

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";
}

以下结果将打印到控制台:

Before calling async method
System.Threading.Tasks.Task`1[System.String]
After calling async method

因此,即使方法GetProductAsync被定义为async并且等待了5秒钟,执行仍然失败,还请注意,异步方法内部还有一个Console.WriteLine("Inside async method after await");没有打印!而且返回值也不会被打印!

那么这是怎么回事?仅仅因为该方法被定义为异步方法,并且其中有一个等待状态,并不意味着可以保证调用者被异步执行! 特别是调用Main的方法不会await ,因此这就是失败的原因。

现在,如果更改了代码并且Main正在等待GetProductAsync方法:

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";
}

现在打印到控制台的结果是:

Before calling async method
Inside async method after await
After calling async method
Got all Products

因此,在这种情况下,结果已经在main内部正确等待了,执行返回给调用者,并且现在可以继续执行其他任务,例如更新GUI(不是这种情况)在这个简单的控制台应用中)。 希望这可以说明这里发生的情况,基本上,在这种情况下,Main的调用方也需要等待异步GetProductAsync方法的结果才能看到结果。

本文很好地解释了各种陷阱和陷阱!不用太深入 https://www.pluralsight.com/guides/understand-control-flow-async-await