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()
?
You seem to misunderstand the message from Resharper. Instead of applying the
await
operator, you called theTask.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
@MarcGravell has the correct answer; I'm just going to answer this other question:
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 theParallel
class for parallel processing (which used theTask
type underneath). However, in advanced scenarios, you could use theTask
type directly.Task.Wait
was used to wait for those independent tasks to complete.When
async
/await
were introduced in .NET 4.5, the existingTask
type was almost good enough to be used as an abstract "future". So instead of inventing some new "future" type, they just slightly extendedTask
to work as a future.This brings us to today, where
Task
can be used as either:(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 asStart
,Wait
,Result
, andContinueWith
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.await
is notWait
. It is unclear what the code is that is callingStartListening()
, but one option is toawait
it, as suggested:However, in some other cases it may be better to do nothing at all:
or perhaps use
ContinueWith
for a manual continuation. Since theStartListening
method catches any exceptions, there isn't anything wrong with just ignoring the returnedTask
- so what you had already. I would suggest calling itStartListeningAsync
, 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.