public SingleThreadSyncContext(SingleThreadApartment apartment, bool pumpMessages = true) { _apartment = apartment; _pumpMessages = pumpMessages; if (_pumpMessages) { base.SetWaitNotificationRequired(); } var startTcs = new TaskCompletionSource <TaskScheduler>(); void threadStart() { try { SynchronizationContext.SetSynchronizationContext(this); startTcs.TrySetResult(TaskScheduler.FromCurrentSynchronizationContext()); try { foreach ((SendOrPostCallback d, object?state) in _items.GetConsumingEnumerable()) { try { d(state); } catch (Exception ex) { _apartment.AddException(ex); } finally { OperationCompleted(); } } } finally { SynchronizationContext.SetSynchronizationContext(null); _apartment.TrySetCompletion(); } } catch (Exception ex) { if (!startTcs.TrySetException(ex)) { throw; } } } _thread = new Thread(threadStart); _thread.SetApartmentState(ApartmentState.STA); _thread.IsBackground = true; _thread.Start(); this.TaskScheduler = startTcs.Task.Result; }
public async Task Test_async_void_exceptions_are_captured() { await using var apartment = new SingleThreadApartment(); await apartment.Run(async() => { await Task.Yield(); Assert.IsTrue(SynchronizationContext.Current is SingleThreadApartment.SingleThreadSyncContext); async void AsyncVoidMethod0() { await Task.Delay(400); throw new InvalidOperationException(); } async void AsyncVoidMethod1() { await Task.Delay(600); throw new NotSupportedException(); } AsyncVoidMethod0(); AsyncVoidMethod1(); }); apartment.Complete(); try { await apartment.Completion.WithAggregatedExceptions(); Assert.Fail("Must not reach here, expecting exceptions."); } catch (AssertFailedException) { throw; } catch (Exception ex) { apartment.ClearExceptions(); // we expect to see 2 exceptions wrapped as AggregateException Assert.IsTrue(apartment.AnyBackgroundOperation == false); var aggregate = ex as AggregateException; Assert.IsNotNull(aggregate); Assert.IsTrue(aggregate !.InnerExceptions.Count == 2); Assert.IsTrue(aggregate.InnerExceptions[0] is InvalidOperationException); Assert.IsTrue(aggregate.InnerExceptions[1] is NotSupportedException); } }