简体   繁体   中英

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. I have a portable class library to handle all my business logic and web service calls.

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.

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.

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. I have added breakpoints and it enters the login method and gets as far as this 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 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. 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. 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?”

Don't mix blocking and async code. You should go Async all the way. Your deadlock is because the .Result is blocking.

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.

In Your case using a button EventHandler you would do something like this:

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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