public async Task AsyncMethodMutatesGlobalStateWithAwait() { const int expected = 7; await AsyncMethods.MutateGlobalStateAfterASecondAsync(expected); Assert.AreEqual(expected, MutableGlobalState.State); }
public async Task AsyncMethodReturnsTaskOfT() { const string expected = "foo"; var actual = await AsyncMethods .WaitASecondAndReturnAValueAsync(expected); Assert.AreEqual(expected, actual); }
public void SomeProblemWithGetAwaiterGetResult() { var blockingSyncContext = new WindowsFormsSynchronizationContext(); SynchronizationContext.SetSynchronizationContext(blockingSyncContext); var theValue = AsyncMethods .WaitASecondAndReturnAValueAsync("this too is doomed") .GetAwaiter() .GetResult(); }
public void HowDoIFixThisDeadLockByUsingConfigureAwaitFalse() { var blockingSyncContext = new WindowsFormsSynchronizationContext(); SynchronizationContext.SetSynchronizationContext(blockingSyncContext); var theValue = AsyncMethods .WaitASecondAndReturnAValueAsyncAwaitFalse("this works around it") .GetAwaiter() .GetResult(); Assert.AreEqual("this works around it", theValue); }
public void ItCreatesADeadLockWhenCertainSyncContextsGetInvolved() { var blockingSyncContext = new WindowsFormsSynchronizationContext(); SynchronizationContext.SetSynchronizationContext(blockingSyncContext); // Result is invoked on the same thread as the blocking sync context // Because the sync context blocked when calling the async method, // The call to result is deadlocked as it's waiting for the original call // to release the thread. // A way to see this visually is to execute this from a GUI, it would become non responsive. var theValue = AsyncMethods .WaitASecondAndReturnAValueAsync("this is doomed to deadlock") .Result; }
public void HowDoIFixThisDeadLockByAllowingCompletionOnADifferentThread() { var blockingSyncContext = new WindowsFormsSynchronizationContext(); SynchronizationContext.SetSynchronizationContext(blockingSyncContext); Func <Task <string> > returnValueFunc = () => AsyncMethods .WaitASecondAndReturnAValueAsync("this works around it"); //this now executes on a different thread //and wont deadlock when calling result var theValue = Task .Run(returnValueFunc) .Result; Assert.AreEqual("this works around it", theValue); }
public void IGetBetterExceptionInformationWhenUsingGetAwaiterGetResult() { Assert.Throws <AggregateException>(() => { var resultThatWillNeverBe = AsyncMethods .ThrowAnExceptionAfterNSecondAsync(1) .Result; }, "Using result gives you an aggregate exception and this is not as nice as..."); Assert.Throws <SuperSpecificException>(() => { var resultThatWillNeverBe = AsyncMethods .ThrowAnExceptionAfterNSecondAsync(1) .GetAwaiter() .GetResult(); }, "Using get awaiter, and then get result, actually throws the original exception from the awaiter"); }
public async Task WhatHappensWhenTwoOperationsThrowAnExceptionWhenAll() { Exception exceptionThrowByA = null; Exception exceptionThrowByB = null; var aWithExceptionHandler = AsyncMethods .ThrowAnExceptionAfterNSecondAsync(1) .ContinueWith(task => exceptionThrowByA = task.Exception); var bWithExceptionHandler = AsyncMethods .ThrowAnExceptionAfterNSecondAsync(2) .ContinueWith(task => exceptionThrowByB = task.Exception); await Task.WhenAll (aWithExceptionHandler, bWithExceptionHandler); Assert.IsNotNull(exceptionThrowByA, "a - exception is missing"); Assert.IsNotNull(exceptionThrowByB, "b - exception is missing"); }