Свернуть асинхронный реквест и респонс через коллбек в один асинхронный метод
Вопрос несколько творческий и скорее архитектурный.
Задача следующая, есть метод который принимает реквест и есть набор 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() - отправка запроса на второй сервер через сокет и все, этот метод не держит поток до завершения приема всех коллбеков.
Ответы (1 шт):
Так как ответов много, без 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);
}