0

I have the following client-server style pseudo-code:

public void GetGrades() {
   var msg = new Message(...); // request in here
   QueueRequest?.Invoke(this, msg); // add to outgoing queue
}

In another processor class I have a loop :

// check for messages back from server
// server response could be a "wait", if so, wait for real response
// raise MessageReceived event here
// each message is then processed by classes which catch the event

// send new messages to server
if (queue.Any()){
  var msg = queue.Dequeue();
  // send to server over HTTP 
}

I have heavily simplified this code so its easy to see the purpose of my question.

Currently I call this code like so:

student.GetGrades(); // fire and forget, almost

But I have a less than ideal way of knowing when the result comes back, I basically use events:

I raise MessageReceived?.Invoke(this, msg); then catch this at another level StudentManager which sets the result on the specific student object.

But instead I would like to wrap this in async await and have something like so:

var grades = await GetGrades();

Is this possible in such disconnected scenarios? How would I go about doing it?

sprocket12
  • 5,368
  • 18
  • 64
  • 133
  • 1
    How do you know now that RequestSomething has finished? – hardkoded Mar 28 '19 at 14:39
  • @hardkoded I have updated my question – sprocket12 Mar 28 '19 at 14:44
  • If you want to block until the Queued item has been processed, it would seem that the queue is not necessary. What is the purpose of the queue in your case? – Alen Genzić Mar 28 '19 at 14:46
  • 1
    @AlenGenzić The end user may queue many different requests, I want them to be sent the the server in order. Also because the server calls me, I send my message in the response, I have to wait, the queue allows me to keep what I want to send ready for when the call comes in. – sprocket12 Mar 28 '19 at 14:49

1 Answers1

3

You could try using a TaskCompletionSource. You could do something like this

TaskCompletionSource<bool> _tcs; 
public Task GetGrades() {
   var msg = new Message(...); // request in here
   QueueRequest?.Invoke(this, msg); // add to outgoing queue
   _tcs = new TaskCompletionSource<bool>();
   return _tcs;
}

And then when you need to confirm that the task was completed you do.

_tcs.TrySetResult(true);

By doing this you can do:

var grades = await GetGrades();

Of course there are another things to solve here. Where you are going to keep those TaskCompletionSource if you can many calls, and how you can link each message to each TaskCompletionSource. But I hope you get the basic idea.

hardkoded
  • 18,915
  • 3
  • 52
  • 64