I am creating a messaging system and I am facing a problem. I need to Publish a message and wait for the response before returning the Publish function.
This is what my functions look like
public async Task<bool> Publish(int ClientId, string msg){
...
// Wait and check if the client the message was sent to respond
// if that does not happen within 5 seconds, return false, else true
}
private async Task MessageIntercept(int ClientId, string msg){
// Intercepts all messages
...
}
Both of these functions are on the server and the MessageIntercept task is automatically run whenever a message is sent (including the one sent with the Publish method). I can send a message from my asp.net website project by calling on the server project's Publish function mentioned above
Basically what i want to be able to do is call bool Success = Publish(1,"This is a test") and be able to determine whether or not the message was successfully sent, that the client understood and revived the message within 5 seconds.
This is what happens step by step:
PublishMessageIntercept method (which I do not really care about, but the code is written so that all messages are intercepted)MessageIntercept which is where I would like to verify the message before returning the Publish methodExample Message;
Server Message:
{
ClientId: 13,
msg: "Hello World"
}
Client Response:
{
ClientId: 13,
msg: "{Success: true}"
}
MessageIntercept intercepts all messages, including the request just send which should be ignored due to it beeing a request not a response. However once the client responds with a message would I like to tell the Publish method that the response has been successfully completed and then return true. Else if the client does not respond within 5 seconds it should presume false.
You can use a helper method such as this:
public static async Task<bool> WaitFor(Task task, TimeSpan timeout)
{
return await Task.WhenAny(task, Task.Delay(timeout)) == task;
}
Sample usage:
using System;
using System.Threading.Tasks;
namespace Demo
{
public class Program
{
public static async Task Main()
{
if (await WaitFor(MyAsyncMethod(), TimeSpan.FromSeconds(1)))
Console.WriteLine("First await completed");
else
Console.WriteLine("First await didn't complete");
if (await WaitFor(MyAsyncMethod(), TimeSpan.FromSeconds(3)))
Console.WriteLine("Second await completed");
else
Console.WriteLine("Second await didn't complete");
}
public static async Task MyAsyncMethod()
{
await Task.Delay(2000);
}
public static async Task<bool> WaitFor(Task task, TimeSpan timeout)
{
return await Task.WhenAny(task, Task.Delay(timeout)) == task;
}
}
}
For your Publish() method, the call may look like this:
if (await WaitFor(Publish(1, "msg"), TimeSpan.FromSeconds(5)))
...
However, be aware that the disadvantage of using this approach is that if the timeout is exceeded, then any exceptions thrown by the task will not be observed.
If you need to handle any exceptions that may occur after you've given up waiting for the task, you could pass an exception-handling delegate like so:
public static async Task<bool> WaitFor(Task task, TimeSpan timeout, Action<Exception> handleException)
{
var wrapperTask = task.ContinueWith(
t => handleException(t.Exception.InnerException),
TaskContinuationOptions.OnlyOnFaulted);
return await Task.WhenAny(wrapperTask, Task.Delay(timeout)) == task;
}
Then you could call it like this:
public static async Task Main()
{
if (await WaitFor(
MyAsyncMethod(),
TimeSpan.FromSeconds(1),
exception => Console.WriteLine("Exception: " + exception.Message))
)
Console.WriteLine("First await completed");
else
Console.WriteLine("First await didn't complete");
Console.ReadLine();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With