我环顾四周,看了几个关于如何设置的教程,我没有运气。我正在使用Xamarin构建跨平台应用程序。我有一个可移植的类库来处理我的所有业务逻辑和Web服务调用。
我遇到的问题是,当我在下面的方法中运行代码时,它的工作没有问题,但如果我按照下面所示的那样运行它需要很长时间。我相信它已陷入僵局,但正如我对此一样,我无法理解其中的原因。我希望我的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 };
}
}
在ios版本的项目中,在按钮事件中,我使用此代码运行上面显示的任务。
Core.Service.AtmisService service = new Core.Service.AtmisService();
LoginResponse loginTask = service.Login(userName.Text, password.Text).Result;
我认为通过在调用任务结束时使用.Result
时这样设置它会执行此任务并返回结果。我添加了断点,它进入登录方法并获取此var response = await client.GetAsync(uri);
,然后它什么都不做。关于我做错了什么的任何想法。谢谢你的帮助。
答案 0 :(得分:1)
参考这篇文章Async/Await - Best Practices in Asynchronous Programming
“始终异步”意味着你不应该混合同步和 异步代码没有仔细考虑后果。在 特别是,通过调用阻止异步代码通常是个坏主意 Task.Wait或Task.Result。这是一个特别常见的问题 将“脚趾间”浸入异步的程序员 编程,仅转换其应用程序的一小部分 将它包装在同步API中,以便应用程序的其余部分 与变化隔绝。不幸的是,他们遇到了问题 死锁。在MSDN上回答了许多与异步相关的问题之后 论坛,Stack Overflow和电子邮件,我可以说这是迄今为止的 一旦他们学习了基础知识,异步新人最常问的问题: “为什么我的部分异步代码死锁?”
不要混用阻塞和异步代码。你应该一直去Async。你的死锁是因为.Result
正在阻止。
LoginResponse loginTask = await service.Login(userName.Text, password.Text);
总结第二条准则,你应该避免混合异步和 阻止代码。混合异步和阻塞代码可能导致死锁, 更复杂的错误处理和意外的上下文阻塞 线程。本指南的例外是Main方法 控制台应用程序,或 - 如果您是高级用户管理a 部分异步代码库。
答案 1 :(得分:0)
在使用按钮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)
}
您可以找到有关避免死锁的更多信息here。