简体   繁体   English

使用httpclient的任务并返回无法正常工作的值

[英]Task using httpclient and returning a value not working correctly

I've looked around and followed a few tutorials on how to set this up and I'm having no luck. 我环顾四周,并遵循了一些有关如何进行此设置的教程,但我没有运气。 I'm building a cross platform app using Xamarin. 我正在使用Xamarin构建跨平台应用程序。 I have a portable class library to handle all my business logic and web service calls. 我有一个可移植的类库来处理我的所有业务逻辑和Web服务调用。

The issue I'm having is when I run the code within the method below it works without an issue however if I run it as shown below as a task it takes a long time. 我遇到的问题是,当我在下面的方法中运行代码时,它可以正常工作,但是如果我将其作为任务运行,如下图所示,则需要很长时间。 I believe its deadlocked but as I'm new to this I can't understand why. 我相信它陷入僵局,但是由于我是新手,所以我不明白为什么。 I want my Api calls to be in the PCL so I can share it between each platfrom. 我希望我的Api呼叫位于PCL中,以便我可以在每个平台之间共享它。

public async Task<LoginResponse> Login(string userName, string password)
{
    HttpClient client = new HttpClient();
    string baseUrl = "http://someURLhere/";

    client.BaseAddress = new Uri(baseUrl);

    string authData = string.Format("/IOSLogin?Username={0}&Password={1}&languageSettingOnDevice={2}", userName, password, "en");

    var uri = new Uri(string.Format("{0}{1}", baseUrl, authData));

    var response = await client.GetAsync(uri);
    if (response.IsSuccessStatusCode)
    {
       var content = await response.Content.ReadAsStringAsync();

       LoginResponse jsonResponse = JsonConvert.DeserializeObject<LoginResponse>(content);
       jsonResponse.loginSuccesfull = true;
       return jsonResponse;
    }
    else
    {
       return new LoginResponse() { loginSuccesfull = false };
    }
}

In the project for the ios version, on a button event I use this code to run the task shown above. 在ios版本的项目中,在按钮事件上,我使用此代码运行上面显示的任务。

Core.Service.AtmisService service = new Core.Service.AtmisService();
LoginResponse loginTask = service.Login(userName.Text, password.Text).Result;

I thought that by setting it up this way when I use .Result at the end of call to the task it would execute this task and return the result. 我认为,通过在调用任务结束时使用.Result时以这种方式进行设置,它将执行此任务并返回结果。 I have added breakpoints and it enters the login method and gets as far as this var response = await client.GetAsync(uri); 我添加了断点,它进入了登录方法,并得到了这个var response = await client.GetAsync(uri); and then it simply does nothing. 然后它什么都不做。 Any ideas on what I am doing wrong. 关于我在做什么的任何想法。 Thank you for any help. 感谢您的任何帮助。

Referencing this article Async/Await - Best Practices in Asynchronous Programming 参考本文Async / Await-异步编程的最佳实践

“Async all the way” means that you shouldn't mix synchronous and asynchronous code without carefully considering the consequences. “一路异步”意味着您应在不仔细考虑后果的情况下混合使用异步代码。 In particular, it's usually a bad idea to block on async code by calling Task.Wait or Task.Result. 特别是,通过调用Task.Wait或Task.Result阻止异步代码通常是一个坏主意。 This is an especially common problem for programmers who are “dipping their toes” into asynchronous programming, converting just a small part of their application and wrapping it in a synchronous API so the rest of the application is isolated from the changes. 对于程序员来说,这是一个特别普遍的问题,他们将自己的脚步“浸入”异步编程中,只转换其应用程序的一小部分并将其包装在同步API中,从而使应用程序的其余部分不受更改的影响。 Unfortunately, they run into problems with deadlocks. 不幸的是,它们遇到了死锁问题。 After answering many async-related questions on the MSDN forums, Stack Overflow and e-mail, I can say this is by far the most-asked question by async newcomers once they learn the basics: “Why does my partially async code deadlock?” 在MSDN论坛,Stack Overflow和电子邮件上回答了许多与异步相关的问题之后,我可以说这是迄今为止异步新手提出的最基本的问题:“为什么我的部分异步代码会死锁?”

Don't mix blocking and async code. 不要混用阻塞代码和异步代码。 You should go Async all the way. 您应该一直使用Async。 Your deadlock is because the .Result is blocking. 您的死锁是因为.Result被阻止。

you want to do... 你想做...

LoginResponse loginTask = await service.Login(userName.Text, password.Text);

To summarize this second guideline, you should avoid mixing async and blocking code. 总结第二条指南,您应该避免混合使用异步代码和阻塞代码。 Mixed async and blocking code can cause deadlocks, more-complex error handling and unexpected blocking of context threads. 异步和阻塞代码混合会导致死锁,更复杂的错误处理以及上下文线程的意外阻塞。 The exception to this guideline is the Main method for console applications, or—if you're an advanced user—managing a partially asynchronous codebase. 本指南的例外情况是控制台应用程序的Main方法,或者(如果您是高级用户)是管理部分异步代码库的方法。

In Your case using a button EventHandler you would do something like this: 在使用按钮EventHandler的情况下,您将执行以下操作:

private async void myButtonItem_Clicked(object sender, EventArgs e)
        {
            Core.Service.AtmisService service = new Core.Service.AtmisService();
            LoginResponse loginTask = await service.Login(userName.Text, password.Text).ConfigureAwait(false);
            //The rest of the code in this method may run in a different thread than the one that invoked the method. If you have ui code after this then avoid using ConfigureAwait(false)
        }

You can find more information on avoiding deadlocks here . 您可以在此处找到有关避免死锁的更多信息。

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

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