async
-await
together with TaskCompletionSource
pretty much were made for this.
The sender side creates a TaskCompletionSource
, adds it to a dictionary (with key being the id of the request), makes the request and returns the TaskCompletionSource
's Task
.
The receiver then looks into the dictionary to find the right TaskCompletionSource
, removes it from there and sets its result.
The caller of the sender method will await
the returned Task
, which will asynchronously wait for the receiver to process the callback call.
In code, it could look something like this:
// TODO: this probably needs to be thread-safe
// you can use ConcurrentDictionary for that
Dictionary<int, TaskCompletionSource<Result>> requestTcses;
public async Task<Result> MakeApiRequestAsync()
{
int id = …;
var tcs = new TaskCompletionSource<Result>();
requestTcses.Add(id, tcs);
await SendRequestAsync(id);
return await tcs.Task;
}
…
var result = await MakeApiRequest();
var context = await _httpListener.GetContext();
// parse the response into id and result
var tcs = requestTcses[id];
requestTcses.Remove(id);
tcs.SetResult(result);