What does ConfigureAwait(false) do?
Continues the async operation without capturing the current synchronization context, allowing the continuation to run on any thread. Improves performance in libraries where returning to the original context isn’t required.
Why should you usually use ConfigureAwait(false) in libraries?
To avoid deadlocks in UI or ASP.NET contexts and improve performance by not forcing the continuation back to the original context.
Difference between Task.Run(async () => …) and await SomeAsyncMethod()?
What happens if you forget await in an async method?
The async method starts but the calling method doesn’t wait for it, potentially causing unobserved exceptions or race conditions
Difference between blocking and non-blocking calls in HTTPClient: Post() vs PostAsync()?
Post(): Synchronously blocks the calling thread until the request completes.
PostAsync(): Asynchronously sends the request; doesn’t block the calling thread.
When should you use Task.Run in an ASP.NET application?
Only for CPU-bound work that would otherwise block the request thread. For I/O-bound async operations, just use await without Task.Run.
What is the risk of using Task.Run(() => GetDataAsync()) without await?
You may create a nested Task, lose exceptions, and potentially run into unobserved exceptions or unfinished work.
What is the risk of not using ConfigureAwait(false) in library code?
In a UI or ASP.NET context, awaiting may try to resume on the original synchronization context, potentially causing deadlocks or performance issues.
What happens when multiple exceptions occur in parallel tasks?
They are wrapped into an AggregateException.
You were right — Task.WaitAll, Task.WhenAll, or similar APIs wrap multiple exceptions in an AggregateException.
What is the difference between Wait() and await when handling exceptions?
Wait() (or Result) will throw an AggregateException, even if there’s just a single exception.
await will unwrap the exception and throw the original exception (not wrapped).
Q3: What happens if the first completed task in Task.WhenAny throws an exception?
The exception is stored in the returned task.
Task.WhenAny itself doesn’t throw — it just returns the first completed task (success, faulted, or canceled).
You must await the returned task to observe the exception.
var t1 = Task.Run(() => throw new InvalidOperationException());
var t2 = Task.Delay(1000);
var first = await Task.WhenAny(t1, t2);
try
{
await first; // Exception thrown here
}
catch (InvalidOperationException ex)
{
Console.WriteLine($”Caught: {ex.Message}”);
}
IsFaulted and Task.Exception property
var t = Task.Run(() => throw new Exception(“Error”));
t.Wait(); // or just let it finish
if (t.IsFaulted)
Console.WriteLine($”Task failed: {t.Exception.InnerException.Message}”);
What is Task.GetAwaiter()
Every Task (or Task<T>) has a GetAwaiter() method.</T>
Normally, you don’t call it yourself — it’s used by the C# compiler when you write await task;.
Example:
Task<int> task = Task.Run(() => 42);
var awaiter = task.GetAwaiter(); // returns a TaskAwaiter<int></int></int>
int value = await task;
into something like:
var awaiter = task.GetAwaiter();
if (!awaiter.IsCompleted)
{
awaiter.OnCompleted(() => { /* resume method */ });
}
int value = awaiter.GetResult();
👉 You don’t normally call GetAwaiter() directly — unless you’re writing low-level libraries (e.g., custom awaitable types).
Whast is Task.GetResult()
Used internally by await.
Returns the result if task completed successfully, otherwise:
Throws the original exception (not AggregateException).
⚠️ If task is not completed, GetResult() will block until completion.
Task<int> task = Task.Run(() => 1 / 0);
var awaiter = task.GetAwaiter();
try
{
int result = awaiter.GetResult();
}
catch (Exception ex)
{
Console.WriteLine(ex.GetType()); // DivideByZeroException (original)
}</int>
Task.Wait()
Blocks the current thread until the task is finished.
If the task faulted, it throws AggregateException.
Should be avoided in async code (can cause deadlocks in UI or ASP.NET contexts).
Use await instead of Wait() whenever possible.
✅ Prefer
await (best choice for async code)
Lets compiler handle GetAwaiter/GetResult
Exceptions are automatically unwrapped
🚫 Avoid (unless you have good reason)
Wait() and .Result → cause blocking & AggregateException
GetAwaiter() + GetResult() manually → only for low-level libraries or writing custom awaitable logic
: What does Task.Wait() do, and why can it be dangerous?
Wait() blocks the calling thread until the task finishes. If the task throws an exception, it wraps it in an AggregateException. It can cause deadlocks (especially in UI contexts like WinForms/WPF/ASP.NET) and should be avoided in async code.
What does accessing Task.Result do, and why should it be used carefully?
Result blocks the calling thread until the task finishes and then returns the result. If an exception occurs, it’s wrapped in an AggregateException. Like Wait(), it can deadlock in async contexts. Use await instead in async code.
What does GetAwaiter() return, and when is it useful?
GetAwaiter() returns a TaskAwaiter (or ConfiguredTaskAwaiter), which allows fine-grained control over awaiting a task. Normally you don’t call it directly, since await uses it under the hood, but it’s useful when building custom awaiters or writing lower-level async infrastructure.
: What does GetResult() do when called on a task’s awaiter?
GetResult() blocks until the task is finished and returns the result. If the task failed, it throws the original exception (not wrapped in AggregateException). This is different from Wait() and Result.
Why is await task usually preferred over task.Wait() or task.Result?
Because await is non-blocking, avoids deadlocks, unwraps exceptions automatically, and allows the continuation to resume on the right synchronization context. It’s the recommended way in modern async code.
✅ So what’s the difference?
Wait() & Result: block + wrap exception in AggregateException.
GetAwaiter().GetResult(): block + throw original exception.
That’s the real distinction.
None of them are truly “non-blocking” when the task isn’t finished. They all block the calling thread if the task is still running. The only non-blocking way is using await task.
⚠️ Why avoid them?
They block threads → kills the benefit of async.
In UI apps (WinForms, WPF, ASP.NET old synchronization context), they can cause deadlocks.
Best practice: always use await.
What is Task.ContinueWith used for?
It creates a continuation task that runs after the antecedent task completes, regardless of its final state (success, fault, canceled).
What does ContinueWith return?
It returns a new Task (or Task<TResult>) representing the continuation, not the original task.</TResult>