快速背景。在我构建的类库中使用Flurl来简化我的代码,以便与云存储API进行通信。从用于测试所有方法的控制台应用程序调用库时,可以很好地工作。当尝试使用完全相同的类库和简单的winform时,使用控制台应用程序返回的相同方法现在似乎永远不会返回结果。调试时,下面的代码转到" .GetAsync()" line然后永远不会返回结果,也会阻止调试会话继续。不会抛出任何错误消息。
我在Flurl网站上发现了一条评论,似乎有人似乎遇到了同样的问题但是,他们似乎并没有像推荐的那样在这里发布问题。任何可以指向正确方向的东西都会非常感激。
包含在异步方法中的Flurl代码
public async Task<AccountInfo> Authorize()
{
string credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(Utils.ToNonSecureString(accountId) + ":" + Utils.ToNonSecureString(applicationKey)));
var result = await B2UrlType.Authorize
.WithHeader("Authorization", "Basic " + credentials)
.GetAsync()
.ReceiveJson<AccountInfo>();
return result;
}
控制台应用调用完美无缺的代码
if (client == null)
{
var vault = new Vault();
Console.WriteLine("Retrieving account keys");
client = new Client(vault.GetAccountId(), vault.GetApiKey());
Console.WriteLine("Successfully retrieved account keys");
Console.WriteLine("Created new client");
client.Authorize().GetAwaiter().GetResult();
}
Winform调用不返回的代码
private Client client;
public MainWindow()
{
InitializeComponent();
var vault = new Vault();
client = new Client(vault.GetAccountId(), vault.GetApiKey());
client.Authorize().GetAwaiter().GetResult();
}
答案 0 :(得分:1)
您的原始代码会挂起,因为您在调用GetResult()
时阻止了UI线程。这不是Flurl特有的问题;这是async 101。
您的修复有效,因为您不再屏蔽,但您也没有await
拨打Auth()
,这实际上相当于只调用client.Authorize()
{直接来自await
构造函数的{1}}或GetResult()
。你不再阻止,但是你忘了,这意味着MainWindow()
中可能发生的任何异常都将被忽略,导致很难找到的错误。
经验法则:与任何异步库一样,从其他异步方法调用Flurl的异步方法,并尽可能等待它们。在控制台应用程序中,您有来阻止主线程,或者应用程序将在任务完成之前退出。 (我喜欢在最顶层执行此操作 - 定义包含所有工作的client.Authorize
方法并从MainAsync
调用MainAsync().Wait()
。)但是使用WinForms应用程序时,可以放置异步的好地方代码,您永远不会阻止或发送忘记:事件处理程序。
我很长一段时间没有完成WinForms,但基于其他答案,初始化代码似乎是一个不错的事件Main
。移动您的授权电话将是一个很好的解决方案。像这样:
Window.Load
答案 1 :(得分:0)
这是有效的,但我还不确定为什么......
private Client client;
public MainWindow()
{
InitializeComponent();
var vault = new Vault();
client = new Client(vault.GetAccountId(), vault.GetApiKey());
Auth();
}
private async void Auth()
{
await client.Authorize();
}
以异步方式包装授权调用允许httpPost完成并返回结果。