Web API 在处理一些耗时的请求时,往往不能让客户端一直等待响应,否则会造成连接超时或资源浪费的问题。为了解决这个问题,一种常见的设计模式是“异步轮询模式”。这种模式的基本思路是:
1. 客户端发起请求,Web API 立即返回一个“任务 ID”,表示已经接收到请求,并开始后台处理。
2. 客户端根据“任务 ID”,定期向 Web API 发送查询请求,以获取任务的处理进度和状态。
3. Web API 在完成任务后,将结果保存在某个存储中,并更新任务的状态为“完成”。
4. 客户端在查询到任务已经完成后,再向 Web API 发送获取结果的请求,从存储中读取结果并返回给客户端。
这种模式的优点是可以避免客户端长时间等待响应,也可以减轻 Web API 的压力。但是,这种模式的缺点是需要 Web API 维护每个任务的状态和结果的存储位置,增加了 Web API 的复杂度和开销。那么,有没有什么方法可以简化这种模式的实现呢?
我们可以利用 Hangfire 和 AsyncFlow 这两个开源库,来快速实现异步轮询 Web API。
Hangfire 是一个用于 .NET 的后台任务调度库,它可以将任何方法转换为后台任务,并将任务的状态和结果持久化到存储中。
AsyncFlow 是一个用于 ASP.NET Core 的异步轮询 Web API 生成器,它可以根据 Hangfire 的任务自动创建异步轮询 Web API 的终结点。
下面,我们来看看如何使用 Hangfire 和 AsyncFlow 来实现异步轮询 Web API。
Demo
首先,我们需要创建一个 ASP.NET Core 项目,并安装以下几个 NuGet 包:
Hangfire.AspNetCore
Hangfire.MemoryStorage
AsyncFlow
Hangfire.AspNetCore 和 Hangfire.MemoryStorage 是用于配置 Hangfire 的包,这里我们使用内存作为存储。AsyncFlow 是用于生成异步轮询 Web API 的包。
然后,我们需要添加以下代码:
// 堆代码 duidaima.com
// 配置 Hangfire
builder.Services.AddHangfire(config => config.UseMemoryStorage());
builder.Services.AddHangfireServer();
// 配置 AsyncFlow
builder.Services.AddAsyncFlow(options => options.UseMemoryCache());
// 注册业务逻辑类
services.AddTransient<DemoJob>();
...
// 创建异步轮询 Web API
app.MapFlow<DemoJob, DemoRequest, DemoResponse>("demo");
这里,我们使用了 MapFlow 扩展方法来创建异步轮询 Web API。它需要指定三个泛型参数:
DemoJob:业务逻辑类,它需要实现 IAsyncFlow<TRequest, TResponse> 接口。
DemoRequest:请求类型。
DemoResponse:响应类型。
demo 是异步轮询 Web API 的名称。通过这个方法,我们就自动创建了以下四个终结点:
/demo:接收客户端的请求,并返回任务 ID。
/demo/{jobId}/status:根据任务 ID 返回任务的状态。
/demo/{jobId}/result:根据任务 ID 返回任务的结果。
/demo/{jobId}:根据任务 ID 删除任务。
接下来,我们需要实现 DemoJob 类:
public class DemoRequest
{
public string Name { get; set; }
}
public class DemoResponse
{
public string Message { get; set; }
}
public class DemoJob : IAsyncFlow<DemoRequest, DemoResponse>
{
public async Task<DemoResponse> ProcessAsync(DemoRequest request)
{
// 模拟耗时操作
await Task.Delay(20000);
return new DemoResponse{ Message = $"Hello {request.Name}" };
}
}
这里,我们只需要实现 ProcessAsync 方法,在这个方法中,我们可以执行任何业务逻辑,比如调用其他服务,执行数据库操作等。这里,我们只是简单地模拟了一个耗时 20 秒的操作,并返回结果。至此,我们就完成了异步轮询 Web API 的实现。下面,我们来测试一下效果。
测试
首先,我们发送一个请求:
可以看到,返回了一个任务 ID。接下来,我们就可以使用任务 ID 轮询状态,如下图所示:
可以看到,任务的状态是 Processing,表示正在处理中。当任务处理完成后,任务的状态会变为 Succeeded:
这时,我们就可以获取任务的结果了:
可以看到,返回了我们期望的结果。
总结
通过本文的演示,我们可以看到,使用 Hangfire 和 AsyncFlow 可以非常方便地实现异步轮询 Web API 的功能。这样,我们就不需要自己维护每个任务的状态和结果的存储位置,也不需要自己编写异步轮询 Web API 的逻辑。只需要关注业务逻辑的实现即可。