库代码中的ConfigureAwait(false)和事件

时间:2019-02-27 12:54:24

标签: c# asynchronous async-await

因此,我知道我通常应该在库代码中使用ConfigureAwait(false)。例外是当我知道继续将需要调用者上下文时。 但是,如果我不知道会发生这种情况,我不知道该怎么办。我猜我在这种情况下不应该使用ConfigureAwait(false)-但是我想确认一下。

示例:我的班级很少发生以下事件:

public static event TriggeredWebhookInfo WebhookTriggered;
public static event ReadonlyWebhookInfo WebhookCancelled;

有一个方法(它是private返回方法所调用的public Task,但它也使用ConfigureAwait(false)):

private static async Task<HttpResponseMessage> TriggerTaskAsync(string url, WebhookBody body)
{
    if (body == null || url == null)
    {
        WebhookCancelled?.Invoke(url, body);
        Logger.Write(InternalTag.Sender, "Webhook cancelled: " + url, LogType.Normal);
        return null;
    }
    HttpResponseMessage response = await Client.PostAsync(url, GetContent(body)).ConfigureAwait(false);
    WebhookTriggered?.Invoke(url, body, response);
    Logger.Write(InternalTag.Sender, "Webhook triggered: " + url, LogType.Normal);
    return response;
}

现在,对于任何终端应用程序来说,这当然都可以正常工作。但是,如果事件在非终端应用程序中在用户分配的UI上下文上调用方法会发生什么? Invoke()是否可以减轻任何问题,还是应该从调用堆栈中删除对此方法的ConfigureAwait(false)

2 个答案:

答案 0 :(得分:2)

如果要允许方法处理程序具有与调用方相同的上下文,则需要删除ConfigureAwait(false)。也就是说,您可以采用任何一种方式进行操作;重要的是记录您的消费者应该期望的东西。

或者,您可以使用IObservable<T>发布事件,但这要复杂得多,并且会带来另一个(非常重要的)依赖项。

答案 1 :(得分:1)

您必须进行设计调用-是否保证事件在调用公共方法的相同上下文上返回?您的决定基于类似的用例,例如WebClient的{​​{1}},这是在调用DownloadDataCompleted时引发的事件。确定后,明确记录并确保您遵守该规范。

一般来说,我会选择在原始上下文中调用事件的选项。如果呼叫者想将其封送,则始终可以这样做。但是,如果不需要,您将迫使整个DownloadDataAsync链为每次从异步调用返回时的原始contxt争用,一无所有。尽可能保持不受上下文限制,并在可能的最后时刻调回军队。

当然,您可以问自己是否同时需要一个信号和一个返回任务的方法,这两个信号都表示完全相同的异步事件。客户端在监听async事件时是否使用与调用公共异步方法相同的代码?