从 winforms 应用程序调用 Flurl 从来没有 returns 结果
Calling Flurl from winforms app never returns a result
快速背景。在我构建的 class 库中使用了 Flurl,以简化与云存储 api 通信的代码。从用于测试所有方法的控制台应用程序调用库时,效果很好。当尝试将完全相同的 class 库与简单的 winform 一起使用时,return 使用控制台应用程序非常快速地使用的相同方法现在似乎永远不会 return 结果。调试时,下面的代码到达“.GetAsync()”行,然后永远不会 returns 结果并且还会阻止调试会话继续。不会抛出任何错误消息。
我在 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();
}
没有return
的Winform调用代码
private Client client;
public MainWindow()
{
InitializeComponent();
var vault = new Vault();
client = new Client(vault.GetAccountId(), vault.GetApiKey());
client.Authorize().GetAwaiter().GetResult();
}
这是有效的,但我仍然不确定为什么...
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 完成并 return 结果。
您的原始代码挂起,因为您在调用 GetResult()
时阻塞了 UI 线程。这不是 Flurl 特有的问题;这是 async 101.
你的修复工作是因为你不再阻塞,但你也没有 await
调用 Auth()
,这实际上等同于调用 client.Authorize()
没有 await
或 GetResult()
直接来自 MainWindow()
构造函数。你不再阻塞,但你是一劳永逸,这意味着 client.Authorize
中可能发生的任何异常都不会被观察到,从而导致难以追踪的错误。
经验法则:与任何异步库一样,从其他异步方法调用 Flurl 的异步方法并尽可能等待它们。在控制台应用程序中,您必须 在某处阻塞主线程,否则应用程序将在任务完成前退出。 (我喜欢在最上面做——定义一个包含所有工作的 MainAsync
方法并从 Main
调用 MainAsync().Wait()
。)但是对于 WinForms 应用程序,有一个放置异步的好地方无需阻塞或即发即弃的代码:事件处理程序.
我已经有很长一段时间没有使用 WinForms 了,但是根据其他答案,初始化代码似乎是一个不错的事件 Window.Load
。移动您的授权电话将是一个很好的解决方案。像这样:
private async void MainWindow_Load(object sender, System.EventArgs e)
{
await client.Authorize();
}
快速背景。在我构建的 class 库中使用了 Flurl,以简化与云存储 api 通信的代码。从用于测试所有方法的控制台应用程序调用库时,效果很好。当尝试将完全相同的 class 库与简单的 winform 一起使用时,return 使用控制台应用程序非常快速地使用的相同方法现在似乎永远不会 return 结果。调试时,下面的代码到达“.GetAsync()”行,然后永远不会 returns 结果并且还会阻止调试会话继续。不会抛出任何错误消息。
我在 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();
}
没有return
的Winform调用代码private Client client;
public MainWindow()
{
InitializeComponent();
var vault = new Vault();
client = new Client(vault.GetAccountId(), vault.GetApiKey());
client.Authorize().GetAwaiter().GetResult();
}
这是有效的,但我仍然不确定为什么...
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 完成并 return 结果。
您的原始代码挂起,因为您在调用 GetResult()
时阻塞了 UI 线程。这不是 Flurl 特有的问题;这是 async 101.
你的修复工作是因为你不再阻塞,但你也没有 await
调用 Auth()
,这实际上等同于调用 client.Authorize()
没有 await
或 GetResult()
直接来自 MainWindow()
构造函数。你不再阻塞,但你是一劳永逸,这意味着 client.Authorize
中可能发生的任何异常都不会被观察到,从而导致难以追踪的错误。
经验法则:与任何异步库一样,从其他异步方法调用 Flurl 的异步方法并尽可能等待它们。在控制台应用程序中,您必须 在某处阻塞主线程,否则应用程序将在任务完成前退出。 (我喜欢在最上面做——定义一个包含所有工作的 MainAsync
方法并从 Main
调用 MainAsync().Wait()
。)但是对于 WinForms 应用程序,有一个放置异步的好地方无需阻塞或即发即弃的代码:事件处理程序.
我已经有很长一段时间没有使用 WinForms 了,但是根据其他答案,初始化代码似乎是一个不错的事件 Window.Load
。移动您的授权电话将是一个很好的解决方案。像这样:
private async void MainWindow_Load(object sender, System.EventArgs e)
{
await client.Authorize();
}