我正在使用带有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的当前版本是完全异步的。像here描述的旧版本有两个处理程序 - 一个是同步的,一个是异步的(带有Async
后缀)。
答案 0 :(得分:3)
是的,这是一种完全合理的方式。为什么你觉得你可能会滥用这种模式?
这样想:
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
。它所要做的就是创建一个空的延续(因为它基本上是说&#34;当广播完成后,在广播之后运行代码,直到结束大括号&#34;)。或者,如果您愿意,可以保持一致性。
答案 1 :(得分:3)
我的博客上有async
intro,您可能会觉得有帮助。
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);
}