I have the following code that connects to a SignalR Hub
private static async Task StartListening()
{
try
{
var hubConnection = new HubConnection("http://localhost:8080/");
IHubProxy hubProxy = hubConnection.CreateHubProxy("Broadcaster");
hubProxy.On<EventData>("notifyCardAccessEvent", eventData =>
{
Log.Info(string.Format("Incoming data: {0} {1}", eventData.Id, eventData.DateTime));
});
ServicePointManager.DefaultConnectionLimit = 10;
await hubConnection.Start();
Log.Info("Connected");
}
catch (Exception ex)
{
Log.Error(ex);
}
}
In my Form_Load
method, I have this
StartListening();
However, Resharper prompts me to "consider applying the 'await' operator to the result of the call"
So I did this:
Log.Info("Connecting to SignalR hub...");
StartListening().Wait();
Log.Info("Connected!");
However, this causes my UI thread to hang and Connected!
is never printed to the log file.
So my question is, when should I use Wait()
? What are the instances and scenarios that I should use Wait(), and when should I not use Wait()
?
await
is not Wait
. It is unclear what the code is that is calling StartListening()
, but one option is to await
it, as suggested:
await StartListening();
However, in some other cases it may be better to do nothing at all:
StartListening(); // drop the Task on the floor
or perhaps use ContinueWith
for a manual continuation. Since the StartListening
method catches any exceptions, there isn't anything wrong with just ignoring the returned Task
- so what you had already. I would suggest calling it StartListeningAsync
, though.
The reason for the deadlock is that if you use Wait
, your UI thread blocks waiting on an asynchronous method to complete, but that asynchronous method is capturing the sync-context, which means in order to process each continuation it tries to get onto the UI thread - which is blocked... on it.
@MarcGravell has the correct answer; I'm just going to answer this other question:
So my question is, when should I use Wait()? What are the instances and scenarios that I should use Wait(), and when should I not use Wait()?
The confusion is coming from the fact that the Task
type is used for two almost completely different things.
Task
was originally introduced in .NET 4.0 as part of the Task Parallel Library. Normally, you would use Parallel LINQ or the Parallel
class for parallel processing (which used the Task
type underneath). However, in advanced scenarios, you could use the Task
type directly. Task.Wait
was used to wait for those independent tasks to complete.
When async
/await
were introduced in .NET 4.5, the existing Task
type was almost good enough to be used as an abstract "future". So instead of inventing some new "future" type, they just slightly extended Task
to work as a future.
This brings us to today, where Task
can be used as either:
- An item of work in a parallel computation.
- An asynchronous future.
(There's a tiny bit of crossover: you can treat parallel work as asynchronous, and in rare situations like Console Main
methods you do need to block on asynchronous tasks; but ignore those for the moment.)
This means that the API for Task
is split along those lines. Members such as Start
, Wait
, Result
, and ContinueWith
belong pretty firmly on the parallel side. In the asynchronous world, await
is more appropriate.
I have a small table at the bottom of my async
intro that has some new (asynchronous) equivalents for the old (parallel) ways of doing things.
You seem to misunderstand the message from Resharper. Instead of applying the await
operator, you called the Task.Wait()
Method. They may seem similar, but they're working completely different.
This nice answer will provide more information about the differences: https://stackoverflow.com/a/13140963/3465395