Exception Handling

Intro

Exception handling in C# uses try, catch, and finally to handle failures and guarantee cleanup. In a production ASP.NET Core API handling 5,000 requests/second, the difference between a well-structured exception strategy and ad-hoc catch (Exception) blocks is the difference between actionable Application Insights traces with full stack context and a wall of swallowed errors that hide the root cause for days. In modern C#, using / await using is the preferred way to ensure Dispose / DisposeAsync runs.

Example:

try
{
    await ProcessAsync(ct);
}
catch (ArgumentException ex)
{
    Console.WriteLine(ex.Message);
    throw;
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
    Log(ex);
    throw;
}
finally
{
    Cleanup();
}

throw keyword

throw is how you signal that code cannot continue normally and must transfer control to an exception handler.

Why we need it

When to use

public static string NormalizeName(string? value)
{
    var name = value ?? throw new ArgumentNullException(nameof(value));
    if (name.Length > 100)
    {
        throw new ArgumentOutOfRangeException(nameof(value), "Name is too long.");
    }

    return name.Trim();
}

Pitfalls

Tradeoffs

Questions


Whats next