Plugin.ExceptionListeners 1.0.2

There is a newer version of this package available.
See the version list below for details.
dotnet add package Plugin.ExceptionListeners --version 1.0.2
                    
NuGet\Install-Package Plugin.ExceptionListeners -Version 1.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Plugin.ExceptionListeners" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Plugin.ExceptionListeners" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="Plugin.ExceptionListeners" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Plugin.ExceptionListeners --version 1.0.2
                    
#r "nuget: Plugin.ExceptionListeners, 1.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Plugin.ExceptionListeners@1.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Plugin.ExceptionListeners&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=Plugin.ExceptionListeners&version=1.0.2
                    
Install as a Cake Tool

โš ๏ธ Plugin.ExceptionListeners

<div align="center">

Icon

</div>

CI .NET NuGet NuGet Downloads GitHub Release License GitHub Pages

A comprehensive exception listening framework for .NET applications, providing unified exception handling across different exception sources and MAUI cross-platform applications.


๐Ÿ“ฆ Features

  • First-Chance Exception Listening: Capture exceptions as they occur, before they're handled by application code
  • Unhandled Exception Monitoring: Catch exceptions that would otherwise terminate your application
  • Task Exception Handling: Monitor unobserved exceptions from async Tasks and automatically mark them as observed
  • MAUI Cross-Platform Support: Native exception handling for iOS, Android, macOS, and Windows platforms
  • Unified Event Model: All exception sources use the same ExceptionEventArgs interface for consistent handling
  • Automatic Resource Management: Implements IDisposable pattern for proper cleanup and event unsubscription
  • Type-Safe Listener Classes: Strongly typed listener implementations prevent registration errors
  • Background Exception Monitoring: Non-blocking exception listeners that don't interfere with application performance
  • Platform-Specific Native Handling: Automatically handles platform-specific exceptions like NSException, Java.Lang.Throwable, and Win32 exceptions
  • Configurable Listening: Enable/disable specific exception types based on your monitoring needs
  • Lightweight & Efficient: Minimal overhead with optimized event handling and memory usage
  • Framework Integration: Easy integration with logging frameworks like Serilog, NLog, and Microsoft.Extensions.Logging
  • Developer-Friendly API: Simple, intuitive interface that follows .NET conventions and best practices

๐Ÿ› ๏ธ Usage Examples

Basic Exception Handling

using Plugin.ExceptionListeners.Listeners;

// Define a global exception handler
void HandleException(object? sender, ExceptionEventArgs e)
{
    Console.WriteLine($"Exception from {sender?.GetType().Name}: {e.Exception.Message}");
    // Log to your preferred logging framework
    // Send to crash reporting service
    // Notify monitoring systems
}

// Set up exception listeners
using var unhandledListener = new CurrentDomainUnhandledExceptionListener(HandleException);
using var taskListener = new TaskSchedulerUnobservedTaskExceptionListener(HandleException);

// Your application code here - exceptions will be automatically captured

Comprehensive Exception Monitoring

using Plugin.ExceptionListeners.Listeners;

public class ExceptionManager : IDisposable
{
    private readonly List<ExceptionListener> _listeners = new();

    public ExceptionManager()
    {
        // Monitor different exception sources
        _listeners.Add(new CurrentDomainUnhandledExceptionListener(HandleCriticalException));
        _listeners.Add(new TaskSchedulerUnobservedTaskExceptionListener(HandleTaskException));

        // Only enable first-chance in debug builds due to performance impact
#if DEBUG
        _listeners.Add(new CurrentDomainFirstChanceExceptionListener(HandleFirstChanceException));
#endif
    }

    private void HandleCriticalException(object? sender, ExceptionEventArgs e)
    {
        // Log critical exceptions that could crash the app
        Logger.Fatal(e.Exception, "Unhandled exception occurred");
    }

    private void HandleTaskException(object? sender, ExceptionEventArgs e)
    {
        // Handle fire-and-forget Task exceptions
        Logger.Error(e.Exception, "Unobserved task exception");
    }

    private void HandleFirstChanceException(object? sender, ExceptionEventArgs e)
    {
        // Log all exceptions for debugging (high volume!)
        Logger.Debug(e.Exception, "First chance exception");
    }

    public void Dispose()
    {
        foreach (var listener in _listeners)
        {
            listener.Dispose();
        }
        _listeners.Clear();
    }
}

MAUI Cross-Platform Exception Handling

using Plugin.ExceptionListeners.Listeners;
using Plugin.ExceptionListeners.Maui;

public partial class App : Application
{
    private readonly List<ExceptionListener> _listeners = new();

    public App()
    {
        InitializeComponent();
        SetupExceptionHandling();
    }

    private void SetupExceptionHandling()
    {
        // Standard .NET exception listeners
        _listeners.Add(new CurrentDomainUnhandledExceptionListener(HandleException));
        _listeners.Add(new TaskSchedulerUnobservedTaskExceptionListener(HandleException));

        // MAUI-specific native exception listener
        _listeners.Add(new NativeUnhandledExceptionListener(HandleNativeException));
    }

    private void HandleException(object? sender, ExceptionEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine($"Managed Exception: {e.Exception}");
        // Handle .NET managed exceptions
    }

    private void HandleNativeException(object? sender, ExceptionEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine($"Native Exception: {e.Exception}");
        // Handle platform-specific native exceptions (NSException, Java exceptions, etc.)
    }

    protected override void CleanUp()
    {
        foreach (var listener in _listeners)
        {
            listener.Dispose();
        }
        _listeners.Clear();
        base.CleanUp();
    }
}

Integration with Logging Frameworks

using Plugin.ExceptionListeners.Listeners;
using Microsoft.Extensions.Logging;
using Serilog;

// Integration with Microsoft.Extensions.Logging
public class LoggingExceptionHandler
{
    private readonly ILogger<LoggingExceptionHandler> _logger;
    private readonly List<ExceptionListener> _listeners = new();

    public LoggingExceptionHandler(ILogger<LoggingExceptionHandler> logger)
    {
        _logger = logger;

        _listeners.Add(new CurrentDomainUnhandledExceptionListener(HandleUnhandledException));
        _listeners.Add(new TaskSchedulerUnobservedTaskExceptionListener(HandleTaskException));
    }

    private void HandleUnhandledException(object? sender, ExceptionEventArgs e)
    {
        _logger.LogCritical(e.Exception, "Unhandled exception from {Source}", sender?.GetType().Name);
    }

    private void HandleTaskException(object? sender, ExceptionEventArgs e)
    {
        _logger.LogError(e.Exception, "Unobserved task exception");
    }
}

// Integration with Serilog
public class SerilogExceptionHandler
{
    private readonly ILogger _logger = Log.ForContext<SerilogExceptionHandler>();

    private void HandleException(object? sender, ExceptionEventArgs e)
    {
        _logger.Error(e.Exception, "Exception caught from {Source}: {ExceptionType}",
            sender?.GetType().Name ?? "Unknown",
            e.Exception.GetType().Name);
    }
}

Performance Considerations

using Plugin.ExceptionListeners.Listeners;

public class OptimizedExceptionHandling
{
    public void SetupProductionListeners()
    {
        // For production: Only monitor critical exceptions
        var unhandledListener = new CurrentDomainUnhandledExceptionListener(HandleCriticalException);
        var taskListener = new TaskSchedulerUnobservedTaskExceptionListener(HandleTaskException);

        // Avoid FirstChanceExceptionListener in production - high performance impact
    }

    public void SetupDevelopmentListeners()
    {
        // For development: Monitor all exceptions for debugging
        var unhandledListener = new CurrentDomainUnhandledExceptionListener(HandleException);
        var taskListener = new TaskSchedulerUnobservedTaskExceptionListener(HandleException);
        var firstChanceListener = new CurrentDomainFirstChanceExceptionListener(HandleFirstChanceException);
    }

    private void HandleCriticalException(object? sender, ExceptionEventArgs e)
    {
        // Minimal, fast logging for production
        Console.WriteLine($"CRITICAL: {e.Exception.GetType().Name}: {e.Exception.Message}");
    }

    private void HandleFirstChanceException(object? sender, ExceptionEventArgs e)
    {
        // Detailed logging for development (can be very verbose!)
        if (ShouldLogException(e.Exception))
        {
            Console.WriteLine($"FirstChance: {e.Exception}");
        }
    }

    private bool ShouldLogException(Exception exception)
    {
        // Filter out noisy exceptions like HttpRequestException, SocketException, etc.
        return !exception.GetType().Namespace?.StartsWith("System.Net") == true;
    }
}

Platform-Specific Exception Handling

using Plugin.ExceptionListeners.Listeners;
using Plugin.ExceptionListeners.Maui;

public class PlatformSpecificExceptionHandler
{
    public void SetupPlatformListeners()
    {
#if ANDROID
        // Android-specific exception handling
        var nativeListener = new NativeUnhandledExceptionListener(HandleAndroidException);
        // Automatically handles Java exceptions and JNI exceptions
#elif IOS
        // iOS-specific exception handling
        var nativeListener = new NativeUnhandledExceptionListener(HandleiOSException);
        // Automatically handles NSException and Objective-C exceptions
#elif WINDOWS
        // Windows-specific exception handling
        var nativeListener = new NativeUnhandledExceptionListener(HandleWindowsException);
        // Handles Win32 exceptions and SEH exceptions
#elif MACCATALYST
        // macOS Catalyst exception handling
        var nativeListener = new NativeUnhandledExceptionListener(HandleMacException);
#endif
    }

    private void HandleAndroidException(object? sender, ExceptionEventArgs e)
    {
        // Handle Android native exceptions
        if (e.Exception.Data.Contains("AndroidException"))
        {
            System.Diagnostics.Debug.WriteLine($"Android Native: {e.Exception}");
        }
    }

    private void HandleiOSException(object? sender, ExceptionEventArgs e)
    {
        // Handle iOS native exceptions
        if (e.Exception.Data.Contains("NSException"))
        {
            System.Diagnostics.Debug.WriteLine($"iOS Native: {e.Exception}");
        }
    }

    private void HandleWindowsException(object? sender, ExceptionEventArgs e)
    {
        // Handle Windows native exceptions
        System.Diagnostics.Debug.WriteLine($"Windows Native: {e.Exception}");
    }

    private void HandleMacException(object? sender, ExceptionEventArgs e)
    {
        // Handle macOS Catalyst exceptions
        System.Diagnostics.Debug.WriteLine($"macOS Native: {e.Exception}");
    }
}

Advanced Exception Filtering and Analysis

using Plugin.ExceptionListeners.Listeners;

public class AdvancedExceptionAnalyzer
{
    private readonly Dictionary<Type, int> _exceptionCounts = new();
    private readonly List<ExceptionListener> _listeners = new();

    public AdvancedExceptionAnalyzer()
    {
        _listeners.Add(new CurrentDomainFirstChanceExceptionListener(AnalyzeException));
        _listeners.Add(new CurrentDomainUnhandledExceptionListener(HandleCriticalException));
        _listeners.Add(new TaskSchedulerUnobservedTaskExceptionListener(HandleTaskException));
    }

    private void AnalyzeException(object? sender, ExceptionEventArgs e)
    {
        var exceptionType = e.Exception.GetType();

        // Count exception frequency
        _exceptionCounts[exceptionType] = _exceptionCounts.GetValueOrDefault(exceptionType) + 1;

        // Filter out common, expected exceptions
        if (IsExpectedException(e.Exception))
        {
            return; // Don't log expected exceptions
        }

        // Log unusual or critical exceptions
        if (IsCriticalException(e.Exception))
        {
            LogCriticalException(e.Exception);
        }

        // Detect exception patterns
        if (_exceptionCounts[exceptionType] > 10)
        {
            LogFrequentException(exceptionType, _exceptionCounts[exceptionType]);
        }
    }

    private bool IsExpectedException(Exception exception)
    {
        // Filter out common framework exceptions
        return exception is HttpRequestException ||
               exception is SocketException ||
               exception is TaskCanceledException ||
               (exception is ArgumentException && exception.Message.Contains("culture"));
    }

    private bool IsCriticalException(Exception exception)
    {
        return exception is OutOfMemoryException ||
               exception is StackOverflowException ||
               exception is AccessViolationException ||
               exception is InvalidProgramException;
    }

    private void LogCriticalException(Exception exception)
    {
        Console.WriteLine($"CRITICAL EXCEPTION: {exception.GetType().Name}: {exception.Message}");
        // Send to monitoring service, crash reporting, etc.
    }

    private void LogFrequentException(Type exceptionType, int count)
    {
        Console.WriteLine($"FREQUENT EXCEPTION: {exceptionType.Name} occurred {count} times");
        // Alert development team about potential issues
    }

    public void PrintStatistics()
    {
        Console.WriteLine("Exception Statistics:");
        foreach (var kvp in _exceptionCounts.OrderByDescending(x => x.Value))
        {
            Console.WriteLine($"  {kvp.Key.Name}: {kvp.Value} occurrences");
        }
    }
}

๐Ÿ“‹ API Overview

Core Classes

  • ExceptionListener - Abstract base class for all exception listeners with IDisposable support
  • ExceptionEventArgs - Event arguments containing the Exception instance for unified handling
  • CurrentDomainFirstChanceExceptionListener - Captures first-chance exceptions from AppDomain
  • CurrentDomainUnhandledExceptionListener - Monitors unhandled exceptions that could crash the app
  • TaskSchedulerUnobservedTaskExceptionListener - Handles unobserved Task exceptions automatically
  • NativeUnhandledExceptionListener (MAUI) - Cross-platform native exception monitoring

Exception Sources

  • First-Chance Exceptions: AppDomain.CurrentDomain.FirstChanceException - All exceptions as they occur
  • Unhandled Exceptions: AppDomain.CurrentDomain.UnhandledException - Exceptions that would terminate the app
  • Task Exceptions: TaskScheduler.UnobservedTaskException - Fire-and-forget Task exceptions
  • Native Exceptions (MAUI): Platform-specific native exceptions from iOS, Android, Windows, macOS

Platform Support

  • .NET Core Applications: Full support for all managed exception listeners
  • MAUI iOS: NSException, Objective-C exceptions, managed exceptions
  • MAUI Android: Java exceptions, JNI exceptions, managed exceptions
  • MAUI Windows: Win32 exceptions, SEH exceptions, managed exceptions
  • MAUI macOS/Catalyst: Native macOS exceptions, managed exceptions

Event Handling

  • Unified Interface: All listeners use EventHandler<ExceptionEventArgs> delegates
  • Exception Information: Access to full Exception object with stack trace and details
  • Source Identification: Sender parameter identifies which listener caught the exception
  • Automatic Cleanup: IDisposable pattern ensures proper event unsubscription

Configuration Options

  • Selective Listening: Enable only the exception types you need to monitor
  • Performance Control: First-chance listeners can be disabled in production for performance
  • Platform Targeting: Conditional compilation for platform-specific exception handling
  • Integration Ready: Works with any logging framework or crash reporting service

๐Ÿ”ง Design Principles

  • Unified Exception Handling: Consistent ExceptionEventArgs interface across all exception sources
  • Resource Management: Proper IDisposable implementation prevents memory leaks and event handler buildup
  • Performance Conscious: Minimal overhead with efficient event handling and optional high-volume monitoring
  • Platform Agnostic: Works across all .NET platforms with specialized MAUI support for mobile and desktop
  • Developer Friendly: Simple API that follows .NET conventions and integrates easily with existing code
  • Production Ready: Configurable logging levels and performance-optimized listeners for different environments

๐Ÿš€ Installation

For .NET Applications

dotnet add package Plugin.ExceptionListeners

For MAUI Applications

dotnet add package Plugin.ExceptionListeners
dotnet add package Plugin.ExceptionListeners.Maui

๐Ÿงช Development

  • Testing: xUnit test framework with comprehensive exception scenarios
  • Build: dotnet build - Supports .NET 9.0
  • Test: dotnet test - Includes platform-specific tests
  • MAUI Platforms: iOS, Android, Windows, macOS Catalyst
  • Documentation: DocFX-powered documentation with examples

๐Ÿ“„ License

MIT โ€” see LICENSE.md for details.


Robust exception monitoring for .NET applications across all platforms and devices.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net9.0

    • No dependencies.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on Plugin.ExceptionListeners:

Package Downloads
Plugin.ExceptionListeners.Maui

Plugin.ExceptionListeners for .NET MAUI

Bluetooth.Core

Bluetooth.Core for .NET

Bluetooth.Maui

Bluetooth.Maui for .NET Maui

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.5 123 1/7/2026
1.0.4 106 1/5/2026
1.0.3 576 11/21/2025
1.0.2 265 11/5/2025
1.0.1 225 10/28/2025
1.0.0 236 10/27/2025