SynchronizationContext не передается при использовании await
Мы планируем использовать async / await в наших моделях представления MVVM, но столкнулись с серьезной проблемой при модульном тестировании этого кода. При использовании NUnit и написанного от руки макета для наших сообщений мы теряем текущийSynchronizationContext
.
Лучше всего показывать следующий небольшой пример кода:
[Test] public void TestMethod()
{
Func<Task> asyncMethod = async () =>
{
var context = SynchronizationContext.Current;
await TaskEx.Yield();
Assert.AreEqual(context, SynchronizationContext.Current);
};
// Establish the new context
var syncCtx = new SingleThreadSynchronizationContext(false);
SynchronizationContext.SetSynchronizationContext(syncCtx);
// Invoke the function and alert the context to when it completes
var t = asyncMethod();
t.ContinueWith(delegate { syncCtx.Complete(); }, TaskScheduler.Default);
// Pump continuations and propagate any exceptions
syncCtx.RunOnCurrentThread();
t.GetAwaiter().GetResult();
}
На самом деле большая часть этого кода украдена из реализации AsyncPump от Стивена Таубав своем блоге.
Интересное все, что нужно для прохождения этого теста, бросается вExecutionContext.SuppressFlow();
перед вызовом асинхронного метода. Этого может быть достаточно, чтобы решить нашу проблему, но я недостаточно знаю о ExecutionContext, и я хочу немного глубже понять, что происходит.
Почему код, сгенерированный оператором await, поглощает текущий SynchronizationContext?
Есть ли другой очевидный способ использования однопоточного контекста для модульного тестирования асинхронного / ожидающего кода?
PS: мы используем .Net4 и Microsoft.CompilerServices.AsyncTargetingPack.Net4
PPS: это также происходит в простом проекте с использованием стабильного Microsoft.Bcl.Async вместо ATP