Reputation: 12887
I'm using SignalR 2.0.1 with PersistentConnection
(not hubs) and currently my default very simple OnReceived handler looks like this:
protected override Task OnReceived(IRequest request, string connectionId, string data)
{
return Connection.Broadcast(data);
}
I want to add some I/O-bound code to this handler, like accessing a DB on a different machine. Naturally I want everything to be asynchronous and I don't want to block the thread so I'm hoping to use an async flavor like db.SaveChangesAsync()
of EF6 (instead of the regular blocking db.SaveChanges
).
I added the db.SaveChangesAsync()
to the handler, but I need to await
on it too. So I've also added an async
modifier to the handler, but this caused an error with my return value - I can't return Connection.Broadcast(data)
anymore.
This is what I got eventually:
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);
}
Is this the correct way to do this? Because I have a feeling I'm abusing the pattern.
btw, if I understand correctly, the current version of SignalR is fully asynchronous. Older versions like the one described here had two handlers - one synchronous and one asynchronous (with the Async
postfix).
Upvotes: 2
Views: 931
Reputation: 456527
I have an async
intro on my blog that you may find helpful.
A Task
instance represents a "future". So when you're doing this:
protected override Task OnReceived(IRequest request, string connectionId, string data)
{
return Connection.Broadcast(data);
}
You're saying "OnReceived
is done when Connection.Broadcast(data)
is done". This is practically the same as:
protected override async Task OnReceived(IRequest request, string connectionId, string data)
{
await Connection.Broadcast(data);
}
Which is saying "OnReceived
will (asynchronously) wait for Connection.Broadcast(data)
to be done, and then OnReceived
will be done." It's slightly more efficient without the async
and await
, but they have practically the same semantics.
So, yes, this code would be correct:
protected override async Task OnReceived(IRequest request, string connectionId, string data)
{
// some EF code here..
await db.SaveChangesAsync();
await Connection.Broadcast(data);
}
Upvotes: 3
Reputation: 8380
Yes, that is a perfectly reasonable way of going about it. Why do you feel that you may be abusing the pattern?
Think of it this way:
void
corresponds to an async method returning Task
. Likewise, T
corresponds to an async method returning Task<T>
.That is why you cannot do
protected override async Task OnReceived(IRequest request, string connectionId, string data)
{
return Connection.Broadcast(data);
}
, since the async
keyword and your return statement would indicate a method that returned Task<Task>
.
What you can do is remove your last await
altogether. All it will do is create an empty continuation (because it is essentially saying "when the broadcast is done, run the code after the broadcast and until the ending curly brace"). Or you can leave it in for consistency, if you prefer.
Upvotes: 3