HttpClient中的GetAsync无法按预期工作

时间:2015-04-17 17:17:17

标签: c# async-await

我不熟悉async/await的工作原理。为了更好地理解它,我在下面创建了一个示例代码:

    static void Main(string[] args)
    {
        GetAPI();
        Console.WriteLine("Hello");
        Console.ReadLine();
    }

    public static async void GetAPI()
    {
        using (HttpClient client = new HttpClient())
        {
            client.DefaultRequestHeaders.Add("Get", "application/json");

            var response = await client.GetAsync("http://somelinks");

            string content = await response.Content.ReadAsStringAsync();
            Console.WriteLine(content);
            Console.ReadLine();
        }
    }

GetAPI()方法基本上会调用一个以Json格式返回某些内容的API。但是,我收到的输出是......令人惊讶的,尽管首先调用GetAPI(),但首先在控制台中打印“Hello”。当我设置调试器时,在它到达await中的GetAPI()之后,它似乎就会回到Main

如何首先从API打印内容?换句话说,我如何确保程序首先执行GetAPI()中的所有内容?

其他信息:

  1. 我被迫使用async/await,因为HttpClient仅提供GetAsync方法。
  2. 我无法在async/await中使用Main。它给我一个错误说Error 1 'ConsumeWebApi.Program.Main(string[])': an entry point cannot be marked with the 'async' modifier

4 个答案:

答案 0 :(得分:1)

您应该从我认为的异步方法返回任务。

然后你可以等待返回,如下:

    static void Main(string[] args)
    {
        GetAPI().Wait();
        Console.WriteLine("Hello");
        Console.ReadLine();
    }

    public static async Task GetAPI()
    {
        using (HttpClient client = new HttpClient())
        {
            client.DefaultRequestHeaders.Add("Get", "application/json");
            var response = await client.GetAsync("http://google.com/");

            string content = await response.Content.ReadAsStringAsync();
            Console.WriteLine(content);
            Console.ReadLine();
        }
    }

答案 1 :(得分:1)

您有两个选项可以为您提供所需的行为:

  • 将您的GetAPI方法更改为不是异步,并将其称为“已经

如果您的目标只是让这个调用同步,以便您的console.write打印,以便您可以从方法声明中删除异步,不要使用await和do .result,如下所示:

    private void LoadData()
    {
        using (HttpClient client = new HttpClient())
        {
            client.DefaultRequestHeaders.Accept.Add(
                new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));


            var response = client.GetAsync("http://somelinks").Result;

            string content = response.Content.ReadAsStringAsync().Result;
            Console.WriteLine(content);
            Console.ReadLine();
        }
    }

您的http标头请求json不正确您有一个名为'get'的标题。

  • 将您的方法保留为异步并返回一个任务,并使用.Wait()在您从控制台应用程序调用它时完成该任务。

如果要进行异步调用,则需要从异步方法调用它或使用wait等待它完成。通常在事件处理程序中,您只需将事件处理程序标记为异步,并确保从异步方法返回一种Task。

在像您的情况一样的控制台程序中,您可以等待异步方法。您需要从异步方法返回类型任务而不是像您一样无法等待它。这将允许您在完成并移动到WriteLine之前等待异步方法完成。尽管如此,它仍然可以实现同步,并且这两种方法在您的控制台应用程序中的行为相同。

 static void Main(string[] args)
 {
    Console.WriteLine("here");
    LoadData().Wait();
    Console.WriteLine("there");
 }

static async private Task LoadData()
{
    using (HttpClient client = new HttpClient())
    {
        client.DefaultRequestHeaders.Accept.Add(
            new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

        var response = await client.GetAsync("http://somelinks");

        string content = await response.Content.ReadAsStringAsync();
        Console.WriteLine(content);
        Console.ReadLine();
    }
}

一般情况下,最好将方法保留为异步,因为如果将其移动到程序使用的共享库中,该程序可以从需要它的async方法中受益,并在需要的位置同步比如你的控制台应用程序。你最终能够这样做。

答案 2 :(得分:0)

建议的答案是在从Main()调用async方法时使用.Wait()。 E.g。

// call this async method and wait for it to finish
GetApi().Wait();

// do something that should only happen when the async method is over

await / async技术创建了一些后台工作,在等待某事之前无需同步。很明显,OP希望在继续之前等待GetAPI完成,并且主要方法可能不希望退出仍在继续的工作。

答案 3 :(得分:-1)

我还在学习这个(2周前有这个,但是讲师告诉我们,如果它有效,我们使用一些控件很重要。

我不知道它是否会帮助你,但我可以尝试编写我们已经学会使用的代码:

如果您在代码中实现它并根据需要进行更改,则可能会有效。

首先,您的返回类型应始终以Task开头(如果我的讲师是对的)

public async static Task<List<string>> Test()
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(@"http://thebaseadres.net/api/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(
                    new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

                HttpResponseMessage response = await client.GetAsync("lastbitofurl");
                if (response.IsSuccessStatusCode)
                {
                    string s = await response.Content.ReadAsStringAsync();
                    List<String> test = JsonConvert.DeserializeObject<List<string>>(s);
                    return test;
                }
                else
                    return null;
            }
        }

修改

你说你因为主要内容而被迫使用异步,但是你不能在mainpage_loaded上输入你的GetApi()方法吗?

这样的事情:

    async void MainPage_Loaded(object sender, RoutedEventsArgs e)
    {
        await GetAPI();
    }