从单独的程序集中调用异步扩展方法

问题描述 投票:0回答:2

我在单独的程序集中遇到了关于异步扩展方法的怪异行为。

我们有以下内容:

  1. [一个组件处理EventGridEvent的发送。目标是.NET Standard 2.0。该程序集引用Microsoft.Azure.EventGrid
  2. 使用装配号的一个装配。 1.目标是.NET Framework 4.7。

由于某种原因,从汇编编号中创建同步方法。 2至组装号1导致奇怪的行为。考虑一下装配号中的两个功能。 1:

    public async Task PublishAsync(...)
    {
        await _eventGridClient.PublishEventsAsync(_eventGridTopicHostName, ...);
    }

    public void Publish(...) 
    {
        _eventGridClient.PublishEventsAsync(_eventGridTopicHostName, ...).Wait();
    }

如果我们从程序集编号中调用第一个方法, 2 PublishAsync().Wait(),它将永远不会返回。但是,Publish()将。但是,如果Publish()调用PublishAsync().Wait(),该方法也会挂起。

值得一提的是EventGridClient包含LongRunningOperationRetryTimeout,默认设置为30,将其忽略。它永远不会返回。

任何人都不知道是什么原因导致了这种行为?一种解决方法是复制代码,但我们希望避免这种情况。

提前感谢。

c# .net asynchronous .net-standard
2个回答
2
投票

您绝对不应通过在返回的Wait()上调用.ResultTask来阻止异步代码。 @Stephen Cleary解释了为什么on his blog

当调用_eventGridClient.PublishEventsAsync时,将捕获SynchronizationContext。任务完成后,它将等待上下文可用,但是永远不会,因为您正在通过调用.Wait()来阻止它。这会导致死锁。

您可能会避免通过调用ConfigureAwait(false)来捕获上下文而遇到麻烦:

public async Task PublishAsync(...)
{
    await _eventGridClient.PublishEventsAsync(_eventGridTopicHostName, ...)
        .ConfigureAwait(false);
}

但是最好的解决方案仍然是完全不阻塞。异步代码应该是“一路异步”,如链接的博客文章中所述。


0
投票

问题是调用方法正在UI线程上运行。通过像这样包装调用即可解决:Task.Run(() => ...).Wait()

© www.soinside.com 2019 - 2024. All rights reserved.