Bob Horn
Bob Horn

Reputation: 34297

Synchronization context not preserved with async/await?

I've recently changed some code to be asynchronous, using the async/await pattern.

This code is now creating an exception:

private async void Refresh(object stateInfo)
{
    await Task.Factory.StartNew(HydrateServerPingDtoList);
    // more code here
}

private void HydrateServerPingDtoList()
{
    // more code here.
    // Exception occurs on this line:
    this._serverPingDtoList.Add(new ServerPingDto() { ApplicationServer = server });
}

The exception:

This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.

_serverPingDtoList is the backing field for a WPF-bound property. Since I thought that async-await preserved the synchronization context, why would I get this error?

Upvotes: 2

Views: 1811

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456322

await restores the SynchronizationContext within its own async method. It will not propagate it to a background thread that you start via StartNew.

On a side note, StartNew should not be used in async code; I explain why in detail on my blog. You should use Task.Run to execute CPU-bound code.

However, any UI updates (including updates of data-bound properties) should be done on the UI thread, not on a background task. So, assuming that your HydrateServerPingDtoList is actually CPU-bound, you can do this:

private ServerPingDto HydrateServerPingDtoList()
{
  // more code here.
  return new ServerPingDto() { ApplicationServer = server };
}

private async Task Refresh(object stateInfo)
{
  var serverPingDto = await Task.Run(() => HydrateServerPingDtoList());
  this._serverPingDtoList.Add(serverPingDto);
  // more code here
}

Upvotes: 11

Related Questions