Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Sync context for testing async background workers
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Threading;
// Custom synchronization context for testing asynchronous background workers.
// See for the full story!
public class AsyncTester : SynchronizationContext, IDisposable
private readonly int _timeoutMs;
private readonly SynchronizationContext _prevSyncContext;
private readonly BlockingCollection<Tuple<SendOrPostCallback, object>> _queue =
new BlockingCollection<Tuple<SendOrPostCallback, object>>();
public static AsyncTester WithTimeout(int timeoutMs)
var sc = new AsyncTester(timeoutMs, Current);
return sc;
public void Uninstall()
if (this != Current) return;
private AsyncTester(int timeoutMs, SynchronizationContext prevContext)
_timeoutMs = timeoutMs;
_prevSyncContext = prevContext;
public void Dispose()
public override void Post(SendOrPostCallback d, object state)
_queue.Add(Tuple.Create(d, state));
public void ProcessQueue(int timeoutMs = 0)
// Use the constructor-specified timeout if not overridden.
if (timeoutMs <= 0)
timeoutMs = _timeoutMs;
var sw = Stopwatch.StartNew();
while (true)
var timeLeft = (int)(timeoutMs - sw.ElapsedMilliseconds);
if (timeLeft <= 0)
break; // we're done waiting
Tuple<SendOrPostCallback, object> tuple;
if (_queue.TryTake(out tuple, timeLeft))
// Item1 = the callback, Item2 = the state object.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment