从 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()没有 awaitGetResult() 直接来自 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();
}