简体   繁体   English

UWP在HttpClient上不起作用

[英]UWP await on HttpClient not working

I am trying get a JSON response from a web API. 我正在尝试从Web API获得JSON响应。

I am able to retrive response in Console application with similar code, however in UWP await httpClient.GetAsync(uri); 我可以使用类似的代码在控制台应用程序中检索响应,但是在UWP中await httpClient.GetAsync(uri); does not work as expected. 不能按预期工作。

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

}

Code behind: 后面的代码:

private void Button_Click(object sender,RoutedEventArgs e){

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

}

What is does not work here means? 这里不起作用是什么意思?

It is supposed to connect to URL and fetch the response and response should be assigned some value. 它应该连接到URL并获取响应,并且应该为响应分配一些值。 Instead on debug with either step into or Continue the control exits the current line skips subsequent lines too. 而是在调试时选择进入或继续,控件退出当前行,也跳过后续行。 (I have put debug on next lines too),The app just freezes. (我也将调试放在了下一行),该应用程序冻结了。

I refereed similar codes for JSON parsing with HTTPClient on Stackoverflow and other blogs , its suggested to use System.Net.Http or Windows.Web.Http 我在Stackoverflow和其他博客上使用HTTPClient了类似的JSON解析代码,建议使用System.Net.HttpWindows.Web.Http

Related Question : how-to-get-a-json-string-from-url 相关问题: 如何从网址获取json字符串

I think tasks are run and its going on forever wait mode , which seems strange as debug mode doesnt show code being run , it just show ready . 我认为任务正在运行并且永远处于等待模式,这似乎很奇怪,因为调试模式不显示正在运行的代码,而只是显示ready There is no exception as well. 也不例外。

Am I doing something wrong or missing some Nuget reference? 我是在做错什么还是缺少一些Nuget参考?

Please suggest. 请提出建议。

PS : Its the same case with httpClient.GetStringAsync method too. PS:httpClient.GetStringAsync方法也是如此。 On Console app this line works but not on UWP 在控制台应用程序上,此行有效,但不适用于UWP

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

Not duplicate of httpclient-getasync-never-returns-on-xamarin-android 不重复的xxmarin-android上httpclient-getasync-never-returns返回

  • Its not Xamarin , even though it is C# based , my code is different , its not WebApiClient or GetInformationAsync method which I am concerned about. 它不是Xamarin,即使它是基于C#的,我的代码也不同,不是我关注的WebApiClient或GetInformationAsync方法。

There're several errors with the code specified that needs to be cured. 指定的代码存在一些错误,需要纠正。 First, mark your event handler async : 首先,将事件处理程序标记为async

private async void Button_Click(object sender, RoutedEventArgs e)

Second, await GetJson and since this is an asynchronous method, it is a better convention to add the suffix "Async" to it's name ; 其次,等待GetJson ,因为这是一个异步方法,所以在名称后添加“ Async”后缀是更好的约定 therefore, await GetJsonAsync : 因此,等待GetJsonAsync

currency_.ROC = await MyClass.GetJsonAsync();

Now, back to GetJsonAsync itself, ReadAsStringAsync and ToObjectAsync should be awaited too: 现在,回到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;//
    }
}

The reason it wasn't working before is that there was a deadlock caused by the context switch between the await call and the synchronous block of .Wait() . 它之前不起作用的原因是,在await调用与.Wait()的同步块之间的上下文切换导致了死锁。 Find more about that here . 在这里找到更多关于它的信息

Your code works fine. 您的代码工作正常。 I regenerated it here below. 我在下面重新生成了它。 Just get rid of that wonky wait call you're doing. 摆脱掉您正在做的那种怪异的等待呼叫。

Do this. 做这个。 Create a new uwp app, paste in the below code and put a breakpoint on the return and see that it gets executed. 创建一个新的uwp应用程序,粘贴以下代码,在返回值上放置一个断点,看看它是否已执行。

It will work regardless if you make your button handler async or not. 无论您是否使按钮处理程序异步,它都将起作用。 If you don't make it asnyc though then the request won't be executed asynchronously 如果您不将其设为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;
        }
    }
}

Might I take this moment for a shameless plug of my UWP lib. 可能我会花点时间为我的UWP库提供一个无耻的插件。 It does this work for you. 它为您完成这项工作。

https://github.com/DotNetRussell/UWPLibrary https://github.com/DotNetRussell/UWPLibrary

In the BasecodeRequestManager.cs file there's a BeginRequest function that does this work async for you. BasecodeRequestManager.cs文件中,有一个BeginRequest函数可以为您异步工作。 The lib has many many other features as well. 该库还具有许多其他功能。

So I tried this by myself. 所以我自己尝试了。 Unfortunately your informations where not complete so a little header: 不幸的是,您的信息还不够完整,标题如下:
For the Json-Handling I used Newtonsoft , because I didnt found the Json.ToObjectAsync in my UWP environment. 对于Json-Handling,我使用Newtonsoft ,因为我没有在UWP环境中找到Json.ToObjectAsync
To create the ExchangeRate - class I used Json2CSharp . 为了创建ExchangeRate类,我使用了Json2CSharp

Here are the ExchangeRate classes: 这是ExchangeRate类:

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

I changed the Button_Click -Method to an async void . 我将Button_Click -Method更改为async void Normally its not recommend to have an async void instead of a async Task . 通常不建议使用async void而不是async Task But because it is a Handler from a UI-Element its not a problem, because the source will not wait anyway and you shouldn't call this methode directly from your code-behind. 但是,因为它是来自UI元素的处理程序,所以这不是问题,因为源代码无论如何也不会等待,因此您不应直接从背后的代码中调用此方法。
The Button_Click -Method: 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
        }

Inside of your GetJson -Method, you need to add an await for your async operations, or add the .Wait() directly after the method and not in a new line. GetJson内部,您需要为异步操作添加一个await,或者直接在方法之后而不是在新行中添加.Wait() You need to do this, because the Task automatically starts to run, when you call the async operation and the .Wait() comes to late. 您需要这样做,因为当您调用异步操作并且.Wait()迟到时,任务会自动开始运行。 So your GetJson-Method looks like this: 因此,您的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
                }
            }
        }

In addition I added a check, if the Request was successful, to be sure, that we have a response. 另外,我添加了一个检查,以确保请求是否成功,以确保我们收到了答复。 How I said before: I think you should return a ExchangeRat e-object instead of a double, but this depends on your context. 我以前怎么说:我认为您应该返回一个ExchangeRat电子对象而不是一个double,但这取决于您的上下文。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM