Вызов основанного на задачах асинхронного одностороннего метода обратного вызова из службы WCF

У меня есть служба WCF, которая использует контракт обратного вызова для уведомления клиентов, аналогично этому

public interface IClientCallback
{
    [OperationContract(IsOneWay = true)]
    void NotifySomething();
}

и сервисный код, называющий это похоже на это

void NotifySomething()
{
    try
    {
        this.callback.NotifySomething();
    }
    catch (Exception ex)
    {
        // Log the exception and eat it
    }
}

Обратите внимание, что по конструкции уведомление о обратном вызове является необязательным, то есть приятно иметь, но не обязательно. Вот почему он помечен как OneWay и реализация ест исключения.

Из-за некоторого недопонимания мы думали, что этого будет достаточно, чтобы использовать метод неблокирующего огня и забывания. Но, конечно, это не было правдой, поэтому при некоторых обстоятельствах он на некоторое время блокируется, что вызывает проблемы, потому что он вызывается из блока, синхронизированного с потоком. Поэтому мы решили сделать его асинхронным, изменив определение следующим образом

public interface IClientCallback
{
    [OperationContract(IsOneWay = true)]
    Task NotifySomething();
}

У меня нет проблем с реализацией клиента, мой вопрос, как вызвать его из сервиса. Вот что я думаю сделать

async void NotifySomething()
{
    try
    {
        await this.callback.NotifySomething();
    }
    catch (AggregateException ex)
    {
        // Unwrap, log the exception(s) and eat it
    }
    catch (Exception ex)
    {
        // Log the exception and eat it
    }
}

Теперь, так как все говорят async void это не хорошая практика, это нормально использовать здесь? Какие еще варианты у меня есть? Каков рекомендуемый способ выполнить это в контексте службы WCF?

1 ответ

Решение

То, как вы написали, довольно безопасно, так как обрабатывает исключения. Вы также можете написать повторно используемый метод расширения, чтобы вам не пришлось его повторять.

Возможно, что-то вроде этого:

public static class Extensions
{
    public static void FireAndForget(this Task task)
    {
        task.ContinueWith(t => 
        {
            // log exceptions
            t.Exception.Handle((ex) =>
            {
                Console.WriteLine(ex.Message);
                return true;
            });

        }, TaskContinuationOptions.OnlyOnFaulted);
    }
}

public async Task FailingOperation()
{
    await Task.Delay(2000);

    throw new Exception("Error");
}   

void Main()
{
    FailingOperation().FireAndForget();

    Console.ReadLine();
}
Другие вопросы по тегам