【问题标题】:Calling Flurl from winforms app never returns a result从 winforms 应用程序调用 Flurl 永远不会返回结果
【发布时间】:2016-12-23 23:39:15
【问题描述】:

快速背景。在我构建的类库中使用了 Flurl,以简化与云存储 api 通信的代码。从用于测试所有方法的控制台应用程序调用库时效果很好。当尝试通过简单的 winform 使用完全相同的类库时,使用控制台应用程序快速返回的相同方法现在似乎永远不会返回结果。调试时,下面的代码会到达“.GetAsync()”行,然后永远不会返回结果,还会阻止调试会话继续。不会抛出任何错误消息。

我在 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();

    }

【问题讨论】:

  • 对于那些寻求解决这个问题的人,我找到了对我有用的方法here

标签: c# winforms flurl


【解决方案1】:

您的原始代码挂起,因为您在调用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();
}

【讨论】:

  • 是的。离开它,用新鲜的眼光回来看看我的错误。我回去发现有几行代码在我构建的库中阻塞。现在测试了大约 4 个小时,没有任何问题。 Flurl 实现使故障排除变得更加容易,并大大减少了代码行数。感谢您的回答和很棒的图书馆。
【解决方案2】:

这是有效的,但我仍然不确定为什么......

    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 完成并返回结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-06
    • 2017-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-18
    • 2011-12-27
    相关资源
    最近更新 更多