Await in Catch & Finally in C#
Understanding `await` in `catch` and `finally` Blocks
In **C# 6.0 and later**, the `await` keyword can be used inside **catch** and **finally** blocks. This allows handling asynchronous exceptions gracefully and performing cleanup operations asynchronously.
Key Features of `await` in `catch` and `finally` Blocks
- Enables **asynchronous exception handling** inside `catch` blocks.
- Allows performing **asynchronous cleanup operations** inside `finally` blocks.
- Improves responsiveness in **I/O-bound operations** like logging and database cleanup.
- Ensures proper **exception propagation** when `await` is used inside `catch`.
Using `await` in `catch` Block
`await` inside `catch` allows logging exceptions asynchronously without blocking execution.
Example: Await in Catch for Asynchronous Logging
using System;
using System.IO;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
try
{
throw new InvalidOperationException("An error occurred!");
}
catch (Exception ex)
{
await LogErrorAsync(ex);
}
}
static async Task LogErrorAsync(Exception ex)
{
await File.WriteAllTextAsync("error.log", $"Error: {ex.Message}");
Console.WriteLine("Error logged asynchronously.");
}
}
// Output:
// Error logged asynchronously.
The **await LogErrorAsync(ex)** inside `catch` ensures that error logging is done asynchronously without blocking execution.
Using `await` in `finally` Block
`await` inside `finally` allows performing **asynchronous cleanup operations** like closing files or releasing database connections.
Example: Await in Finally for Asynchronous Cleanup
using System;
using System.IO;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
StreamWriter writer = new StreamWriter("log.txt");
try
{
await writer.WriteLineAsync("Processing started...");
throw new Exception("Something went wrong!");
}
catch (Exception ex)
{
Console.WriteLine($"Caught exception: {ex.Message}");
}
finally
{
await writer.DisposeAsync(); // Asynchronous cleanup
Console.WriteLine("StreamWriter closed asynchronously.");
}
}
}
// Output:
// Caught exception: Something went wrong!
// StreamWriter closed asynchronously.
The `await writer.DisposeAsync()` inside `finally` ensures the **StreamWriter is closed asynchronously**, preventing resource leaks.
When to Use `await` in `catch` vs `finally`
Scenario | Use `await` in `catch` | Use `await` in `finally` |
---|---|---|
Logging an error asynchronously | ✅ Yes | ❌ No |
Releasing file/database connections | ❌ No | ✅ Yes |
Retrying an operation | ✅ Yes | ❌ No |
Flushing data to storage | ❌ No | ✅ Yes |
Best Practices for Using `await` in `catch` and `finally`
- Use `await` in `catch` for **logging errors** or **retrying operations asynchronously**.
- Use `await` in `finally` for **cleaning up resources asynchronously**.
- Avoid using `await` inside `catch` if an **immediate rethrow** is required.
- Ensure the `Main()` method is `async Task Main()` to **support awaiting in exception handling**.
- Use `.ConfigureAwait(false)` in libraries to prevent **UI thread deadlocks**.