ConfigureAwait (false) и события в коде библиотеки - PullRequest
0 голосов
/ 27 февраля 2019

Так что я знаю, что я должен использовать 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;
}

Теперь, конечно, это прекрасно работает для любого терминального приложения.Однако что произойдет, если событие вызовет метод в контексте пользовательского интерфейса, назначенный пользователем в нетерминальном приложении?Invoke() уменьшит ли какие-либо проблемы, или я должен удалить ConfigureAwait(false) из стека вызовов для этого метода?

Ответы [ 2 ]

0 голосов
/ 27 февраля 2019

Вы должны сделать вызов проекта - гарантированно возвращено ли событие в том же контексте, что вызвало публичный метод, или нет?Основывайте свое решение на аналогичных случаях использования, таких как WebClient DownloadDataCompleted, событие, которое вызывается при вызове DownloadDataAsync.Как только вы решили, задокументируйте это явно и убедитесь, что вы подчиняетесь этой спецификации.

В общем, я бы выбрал вариант , а не , чтобы вызывать событие воригинальный контекст.Если вызывающий абонент хочет сделать маршалинг, он всегда может это сделать.Но если это не нужно, вы заставляете всю свою цепочку async бороться за исходное продолжение каждый раз, когда он возвращается из асинхронного вызова, даром.Будьте максимально свободны от контекста и маршалируйте в самый последний момент.

Конечно, вы можете спросить себя, нужен ли вам как метод события, так и метод возврата к задачам, которые оба сигнализируют одинаковоасинхронное событиеЯвляется ли клиент, прослушивающий событие WebHookTriggered, тем же кодом, который вызывает публичный асинхронный метод?

0 голосов
/ 27 февраля 2019

Если вы хотите, чтобы обработчики методов имели тот же контекст, что и ваш вызывающий объект, вам необходимо удалить ConfigureAwait(false).Тем не менее, вы можете сделать это в любом случае;важно документировать того, что ожидают ваши потребители.

В качестве альтернативы, вы можете использовать IObservable<T> для публикации ваших событий, но это гораздо сложнее и приносит другое (нетривиальная) зависимость.

...