You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET MAUI中Serilog捕获未处理异常无法写入Azure Table问题

问题分析与解决

原因

未处理异常触发后,进程会立即终止,而Serilog的Azure Table Storage sink默认采用异步写入机制——此时异步写入操作还未完成,进程就已退出,导致日志无法持久化到Azure Table。而Debug sink是同步输出,所以能在调试窗口看到日志。

解决方案

1. 强制刷新Serilog日志

在未处理异常的处理器中,调用Log.CloseAndFlush()强制将所有待写入的日志同步刷新到Azure Table,确保写入完成后再让进程继续终止。

2. 覆盖MAUI中所有未处理异常场景

MAUI中存在三种常见的未处理异常触发场景,建议全部处理以覆盖所有情况:

  • AppDomain.CurrentDomain.UnhandledException:处理非UI线程的未处理异常
  • Application.Current.UnhandledException:处理UI线程的未处理异常
  • TaskScheduler.UnobservedTaskException:处理后台Task未被观察到的异常

修改后的代码示例

App.cs 完整代码

public partial class App : Application
{
    private readonly ILogger<App> _logger;

    public App(ILogger<App> logger)
    {
        _logger = logger;
        InitializeComponent();
        
        // 注册三种异常处理器
        AppDomain.CurrentDomain.UnhandledException += HandleAppDomainUnhandledException;
        Application.Current.UnhandledException += HandleApplicationUnhandledException;
        TaskScheduler.UnobservedTaskException += HandleUnobservedTaskException;
        
        MainPage = new AppShell();
    }

    private void HandleAppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        var exception = (Exception)e.ExceptionObject;
        _logger.LogCritical(exception, "AppDomain未处理异常");
        Log.CloseAndFlush();
    }

    private void HandleApplicationUnhandledException(object sender, Microsoft.Maui.Controls.UnhandledExceptionEventArgs e)
    {
        _logger.LogCritical(e.Exception, "UI线程未处理异常");
        Log.CloseAndFlush();
        e.Handled = true; // 标记为已处理,避免系统默认弹窗
    }

    private void HandleUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
    {
        _logger.LogCritical(e.Exception, "后台任务未观察异常");
        Log.CloseAndFlush();
        e.SetObserved(); // 标记为已观察,避免进程因未处理Task异常终止
    }
}

优化Program.cs的Serilog配置顺序

将Serilog Logger的初始化放在builder.Logging.AddSerilog()之前,确保DI容器使用已配置好的Logger:

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                fonts.AddFont("SF-Pro-Text-Bold.otf", "SFProTextBold");
                fonts.AddFont("SF-Pro-Text-Regular.otf", "SFProTextRegular");
                fonts.AddFont("materialdesignicons-webfont.ttf", "MaterialDesignIcons");
            });

        builder.UseMauiApp<App>()
            .UseMauiCommunityToolkit()
            .RegisterDataServices()
            .RegisterViewModels()
            .RegisterViews();

        // 先初始化Serilog Logger
        var storageConnectionString = "MY_CONNECTION_STRING";
        var tableName = "logs";

        Log.Logger = new LoggerConfiguration()
            .WriteTo.AzureTableStorage(connectionString: storageConnectionString, storageTableName: tableName)
            .WriteTo.Debug()
            .CreateLogger();

        // 再将Serilog添加到MAUI日志系统
        builder.Logging.AddSerilog();

        return builder.Build();
    }
}

验证

触发未处理异常后,检查Azure Table Storage,此时异常日志会被正常持久化,同时调试窗口也会输出日志。

内容的提问来源于stack exchange,提问作者adamasan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 07:25:01