c# - 返回之前等待异步函数

标签 c# asp.net asynchronous message-queue messaging

我正在创建一个消息系统,但遇到了问题。我需要发布消息并等待响应,然后再返回发布函数。

这就是我的函数的样子

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
    ...
}

这两个函数都在服务器上,每当发送消息(包括使用 Publish 方法发送的消息)时,MessageIntercept 任务都会自动运行。我可以通过调用上面提到的服务器项目的 Publish 函数从我的 asp.net 网站项目发送消息

基本上我想要做的是调用 bool Success = Publish(1,"This is a test") 并能够确定消息是否已成功发送,即客户在 5 秒内理解并恢复了该消息。

这是一步一步发生的事情:

  1. 我使用 Publish 从服务器向设备发送消息
  2. 消息被 MessageIntercept 方法拦截(我并不真正关心,但编写代码是为了拦截所有消息)
  3. 客户端接收并处理消息
  4. 客户端响应,消息在 MessageIntercept 中被拦截,我想在返回 Publish 方法之前验证消息

消息示例;

服务器消息:

{
    ClientId: 13,
    msg: "Hello World"
}

客户响应:

{
    ClientId: 13,
    msg: "{Success: true}"
}

MessageIntercept 拦截所有消息,包括刚刚发送的请求,该请求应被忽略,因为它是请求而不是响应。但是,一旦客户端响应消息,我想告诉 Publish 方法响应已成功完成,然后返回 true。否则,如果客户端在 5 秒内没有响应,则应假定为 false。

最佳答案

您可以使用如下辅助方法:

public static async Task<bool> WaitFor(Task task, TimeSpan timeout)
{
    return await Task.WhenAny(task, Task.Delay(timeout)) == task;
}

使用示例:

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;
        }
    }
}

对于您的 Publish() 方法,调用可能如下所示:

if (await WaitFor(Publish(1, "msg"), TimeSpan.FromSeconds(5)))
    ...

但是,请注意,使用此方法的缺点是,如果超过超时,则将不会观察到任务抛出的任何异常。

如果您需要处理放弃等待任务后可能发生的任何异常,您可以传递异常处理委托(delegate),如下所示:

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;
}

然后你可以这样调用它:

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();
}

关于c# - 返回之前等待异步函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59374266/

相关文章:

c# - 如何实现返回 Task<T> 的接口(interface)方法?

c# - 使用await顺序调用异步任务有什么好处?

asp.net - WPF 应用程序转换为 ASP

c# - 授权具有角色的属性不起作用?

javascript - javascript本身是同步的,而环境是异步的吗?

c# - 在 .NET 中检测 HDMI 电缆事件?

c# - javascript 中的 Web.config 值

c# - 标准输出阅读器挂起 BCP 工具

c# - 从 C# 代码停止 Windows 服务不起作用

c# - 我可以将图像设置为*不*自动调整大小吗?