UWP 等待 HttpClient 不工作

UWP await on HttpClient not working

我正在尝试从网络 API 获得 JSON 响应。

我可以使用类似的代码在控制台应用程序中检索响应,但是在 UWP 中 await httpClient.GetAsync(uri); 无法按预期工作。

public static async Task<double> GetJson()
{
    using (var httpClient = new HttpClient())
    {
        Uri uri= new Uri("https://api.cryptonator.com/api/ticker/btc-usd");
        HttpResponseMessage response = await httpClient.GetAsync(uri);
        //Below code is not relevent since code is failing on await
        var result = response.Content.ReadAsStringAsync();
        var jsonResponse = Json.ToObjectAsync<ExchangeRate>(result);//
        jsonResponse.Wait();//
        ExchangeRate exchangeRateObj = jsonResponse.Result;//
        return 1.2;//
    }

}

后面的代码:

private void Button_Click(object sender,RoutedEventArgs e){

var ROC__ =  MyClass.GetJson();
ROC__.Wait();
currency_.ROC = ROC__.Result;

}

这里不起作用是什么意思?

它应该连接到 URL 并获取响应并且应该为响应分配一些值。相反,在使用 step into 或 Continue 进行调试时,控件退出当前行也会跳过后续行。 (我也在下一行进行了调试),应用程序冻结了。

我在 Whosebug 和其他博客上参考了 JSON 与 HTTPClient 解析的类似代码,建议使用 System.Net.HttpWindows.Web.Http

相关问题: how-to-get-a-json-string-from-url

我认为任务是 运行 并且它一直在等待模式,这看起来很奇怪,因为调试模式不显示代码是 运行,它只显示 ready。也不例外。

我是不是做错了什么或遗漏了一些 Nuget 参考资料?

求推荐。

PS : httpClient.GetStringAsync 方法也一样。 在控制台应用程序上,此行有效但不适用于 UWP

 var json = new WebClient().DownloadString("https://api.cryptonator.com/api/ticker/btc-usd");

不重复

指定的代码有几个错误需要修复。首先,标记您的事件处理程序 async:

private async void Button_Click(object sender, RoutedEventArgs e)

其次,await GetJson 因为这是一个异步方法,所以最好在它的名称后加上后缀"Async";因此,等待 GetJsonAsync:

currency_.ROC = await MyClass.GetJsonAsync();

现在,回到 GetJsonAsync 本身,ReadAsStringAsyncToObjectAsync 也应该等待:

private static async Task<double> GetJsonAsync()
{
    using (var httpClient = new HttpClient())
    {
        Uri uri = new Uri("https://api.cryptonator.com/api/ticker/btc-usd");
        HttpResponseMessage response = await httpClient.GetAsync(uri);
        string result = await response.Content.ReadAsStringAsync();
        //Below code is not relevent since code is failing on await
        ExchangeRate exchangeRateObj = await Json.ToObjectAsync<ExchangeRate>(result);
        return 1.2;//
    }
}

之前不工作的原因是await调用和.Wait()的同步块之间的上下文切换造成了死锁。查找有关 here.

的更多信息

您的代码运行良好。我在下面重新生成了它。摆脱你正在做的那个不稳定的等待电话。

这样做。创建一个新的 uwp 应用程序,粘贴下面的代码并在 return 上放置一个断点并查看它是否被执行。

无论您是否使按钮处理程序异步,它都会起作用。如果您不将其设为 asnyc,那么请求将不会异步执行

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        SomeClass.GetJson();
    }

}

public class SomeClass
{
    public static async Task<double> GetJson()
    {
        using (var httpClient = new HttpClient())
        {
            Uri uri = new Uri("https://api.cryptonator.com/api/ticker/btc-usd");
            HttpResponseMessage response = await httpClient.GetAsync(uri);
            return 1.2;
        }
    }
}

我可以借此机会无耻地插入我的 UWP 库。它为您完成这项工作。

https://github.com/DotNetRussell/UWPLibrary

BasecodeRequestManager.cs 文件中有一个 BeginRequest 函数可以为您异步完成这项工作。该库还有许多其他功能。

所以我自己试了一下。不幸的是你的信息有点不完整 header:
对于 Json-Handling 我使用了 Newtonsoft,因为我在我的 UWP 环境中没有找到 Json.ToObjectAsync
为了创建 ExchangeRate- class,我使用了 Json2CSharp

这里是汇率 classes:

public class ExchangeRate
    {
        public string Error { get; set; }
        public bool Success { get; set; }
        public Ticker Ticker { get; set; }
        public int Timestamp { get; set; }
    }

public class Ticker
    {
        public string @Base { get; set; }
        public string Change { get; set; }
        public string Price { get; set; }
        public string Target { get; set; }
        public string Volume { get; set; }
    }

我将 Button_Click-Method 更改为 async void。通常不建议使用 async void 而不是 async Task。但是因为它是来自 UI-Element 的处理程序,所以这不是问题,因为无论如何源都不会等待,您不应该直接从 code-behind 调用此方法。
Button_Click-方法:

private async void Button_Click(object sender, RoutedEventArgs e)
        {
            var ROC__ = await MyClass.GetJson();
            //Do whatever you want with the result.
            //Its a double, maybe you want to return an ExchangeRate objcet insted
        }

在您的 GetJson-Method 中,您需要为异步操作添加 await,或者直接在方法之后添加 .Wait() 而不是在新行中。您需要这样做,因为当您调用异步操作并且 .Wait() 迟到时,任务会自动开始 运行。所以你的 GetJson-Method 看起来像这样:

public static async Task<Double> GetJson()
        {

            using (var httpClient = new HttpClient())
            {
                Uri uri = new Uri("https://api.cryptonator.com/api/ticker/btc-usd");
                HttpResponseMessage response = await httpClient.GetAsync(uri);
                if (response.StatusCode == System.Net.HttpStatusCode.OK)
                {
                    var result = await response.Content.ReadAsStringAsync();
                    ExchangeRate rate = JsonConvert.DeserializeObject<ExchangeRate>(result); //Newtonsoft
                    return 1.2;
                }
                else
                {
                    return -1; //Example value
                }
            }
        }

此外,我添加了一个检查,如果请求成功,可以肯定的是,我们有一个响应。我之前是怎么说的:我认为你应该 return a ExchangeRate-object 而不是 double,但这取决于你的上下文。