在 SignalR 2.0 OnReceived 处理程序中调用等待的正确方法
本文关键字:等待 调用 方法 程序 SignalR OnReceived 处理 | 更新日期: 2023-09-27 17:58:42
我正在使用带有PersistentConnection
(不是集线器(的 SignalR 2.0.1,目前我默认的非常简单的 OnReceived 处理程序如下所示:
protected override Task OnReceived(IRequest request, string connectionId, string data)
{
return Connection.Broadcast(data);
}
我想向此处理程序添加一些 I/O 绑定代码,例如访问其他计算机上的数据库。当然,我希望一切都是异步的,我不想阻塞线程,所以我希望使用像 EF6 db.SaveChangesAsync()
这样的异步风格(而不是常规的阻塞db.SaveChanges
(。
我将db.SaveChangesAsync()
添加到处理程序中,但我也需要对其进行await
。所以我也向处理程序添加了一个 async
修饰符,但这导致了我的返回值出错 - 我不能再返回Connection.Broadcast(data)
了。
这是我最终得到的:
protected override async Task OnReceived(IRequest request, string connectionId, string data)
{
// some EF code here..
await db.SaveChangesAsync();
// the original return changes into this?
await Connection.Broadcast(data);
}
这是正确的方法吗?因为我有一种感觉,我在滥用这种模式。
顺便说一句,如果我理解正确,SignalR 的当前版本是完全异步的。像这里描述的旧版本有两个处理程序 - 一个同步和一个异步(带有Async
后缀(。
是的,这是一种完全合理的方法。为什么你觉得你可能在滥用这种模式?
可以这样想:
- 返回
void
的同步方法对应于返回Task
的异步方法。同样 - 返回
T
的同步方法对应于返回Task<T>
的异步方法。
这就是为什么你不能做
protected override async Task OnReceived(IRequest request, string connectionId, string data)
{
return Connection.Broadcast(data);
}
,因为 async
关键字和 return 语句将指示返回Task<Task>
的方法。
您可以做的是完全删除最后的await
。它所做的只是创建一个空的延续(因为它本质上是说"广播完成后,在广播之后运行代码,直到结尾大括号"(。或者,如果您愿意,可以将其保留以保持一致性。
我的博客上有一个async
介绍,您可能会觉得有帮助。
Task
实例代表"未来"。因此,当您执行此操作时:
protected override Task OnReceived(IRequest request, string connectionId, string data)
{
return Connection.Broadcast(data);
}
你是说"OnReceived
当Connection.Broadcast(data)
完成时就完成了"。这实际上与:
protected override async Task OnReceived(IRequest request, string connectionId, string data)
{
await Connection.Broadcast(data);
}
也就是说"OnReceived
将(异步(等待Connection.Broadcast(data)
完成,然后OnReceived
将完成。如果没有async
和await
,效率会稍微高一些,但它们实际上具有相同的语义。
所以,是的,这段代码是正确的:
protected override async Task OnReceived(IRequest request, string connectionId, string data)
{
// some EF code here..
await db.SaveChangesAsync();
await Connection.Broadcast(data);
}