How can I make a POST HTTP request and wait for a callback without blocking the current thread?

We have a .NET application that uses an HTTP-based API, where the request is for a third-party HTTP endpoint (which is not under our control) and it calls us back at a later time on the HTTP endpoint that we give it ; sort of: POST

WebRequest request = WebRequest.Create(urlToMethod);
request.Method = @"POST";
request.Headers.Add(@"Callback", "http://ourserver?id="+id ); 

We make thousands and thousands of calls, and therefore we would like to be as efficient as possible (in terms of speed / memory / threads, etc.).

As for the callback code, we have a type that acts as a listener; so we start:

_httpListener = new HttpListener();
_httpListener.Prefixes.Add(ourServer);
_httpListener.Start();
_httpListener.BeginGetContext(callback, null);

When the server calls us, it calls our method callback, which looks something like this:

HttpListenerContext context = _httpListener.EndGetContext(result);

HttpListenerResponse httpListenerResponse = context.Response;
httpListenerResponse.StatusCode = 200;
httpListenerResponse.ContentLength64 = _acknowledgementBytes.Length;

var output = httpListenerResponse.OutputStream;
output.Write(_acknowledgementBytes, 0, _acknowledgementBytes.Length);

context.Response.Close();

var handler = ResponseReceived;

if (handler != null)
{
    handler(this, someData);
}

, ( HttpListener), ResponseReceived.

(, ) , id. subscriber :

_matchingResponseReceived = new ManualResetEventSlim(false);
_listener.WhenResponseReceived += checkTheIdOfWhatWeGetAndSetTheEventIfItMatches;
postTheMessage();
_matchingResponseReceived.Wait(someTimeout);

, . , , , Listener . Task, , , , .

( TPL ) , , ?

+4
2

async - await TaskCompletionSource .

- TaskCompletionSource, ( , ), TaskCompletionSource Task.

, TaskCompletionSource, .

await Task, , .

:

// 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);
+1

, (, , ). (BTW, "POST" ) , -API, , , ID?

+2

All Articles