Свернуть асинхронный реквест и респонс через коллбек в один асинхронный метод

Рейтинг: 0Ответов: 1Опубликовано: 28.03.2023

Вопрос несколько творческий и скорее архитектурный.

Задача следующая, есть метод который принимает реквест и есть набор event(ов) через который отправляются ответы. К примеру:

interface IClient
{
    void GetSomethingRequest();
}

interface IObserver
{
    event Action SomethingRequestStatus;
    event Action<object> SomethingRequestResponse;
}

В примере есть сендер и обзервер. При вызове метода сендера, мы получаем один коллбек "SomethingRequestStatus" и n коллбеков "SomethingRequestResponse".

Вопрос такой, как правильнее свернуть всю эту конструкцию в один асинхронный метод наподобие слудующего:

interface IClient
{
    public Task<Tuple<bool, object>> GetSomething();
}

Думаю на счет мьютексов, но может есть более верное решение ?

Есть еще вариант с задержкой и проверкой заполнения ответов от коллбеков, однако задержки не подходят так как система должна работать быстро.

Иначе говоря вопрос в том как правильнее переписать старый вариант асинхронного процесса сделанный на основе коллбеков (используется взаимодействие с удаленным сервером через сокеты), на новый лад, где вызывая один метод можно дождаться ответа от системы.

Upd:

Основная проблема не в коллекционировании данных, а в задержки потока до момента прекращения прихода сообщений или же прихода события "SomethingRequestStatus" сигнализирующего о неудачном завершении запроса "client.GetSomethingRequest()".

Дело в том, что это межсервисное взаимодействие, но не по http, а через сокеты. Первый сервер отправляет запрос на второй. Второй сервер отвечает, а первый слушает ответ. т.е. метод client.GetSomethingRequest() - отправка запроса на второй сервер через сокет и все, этот метод не держит поток до завершения приема всех коллбеков.

Ответы

▲ 0Принят

Так как ответов много, без Producer/Consumer не обойтись. Будем считать, что SomethingRequestStatus это сигнал завершения приема данных. Тогда получится примерно такой метод.

public ChannelReader<object> GetSomething(IClient client, IObserver observer)
{
    Channel<object> channel = Channel.CreateUnbounded<object>();
    void dataHandler(object o) => channel.Writer.TryWrite(o);
    void statusHandler()
    {
        observer.SomethingRequestResponse -= dataHandler;
        observer.SomethingRequestStatus -= statusHandler;
        channel.Writer.Complete(); // закрывает канал
    }

    observer.SomethingRequestStatus += statusHandler;
    observer.SomethingRequestResponse += dataHandler;
    client.GetSomethingRequest();
    return channel.Reader;
}

А использовать его так

await foreach (object data in GetSomething().ReadAllAsync())
{
    UseData(data);
}