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

.NET 8中IExceptionHandler内Serilog无法写入SQL Server数据库问题

解决.NET Core 8全局异常处理器中Serilog无法写入SQL Server的问题

问题场景

已配置Serilog将日志写入文件、控制台和SQL Server数据库,在应用其他区域及ExceptionHandlingMiddleware构造函数中,日志均可正常写入数据库,但在TryHandleAsync方法中,仅文件和控制台日志生效,数据库写入失败。相关代码如下:

异常处理器代码

public class ExceptionHandlingMiddleware : IExceptionHandler
{
    private readonly ILogger<ExceptionHandlingMiddleware> _logger;

    public ExceptionHandlingMiddleware(ILogger<ExceptionHandlingMiddleware> logger)
    {
        _logger = logger;
        
        // 可写入文件、控制台及MSSQL数据库
        _logger.LogInformation("1-ExceptionHandlingMiddleware");
    }

    public ValueTask<bool> TryHandleAsync(HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        // 仅文件和控制台日志生效,数据库写入失败
        _logger.LogInformation("2-ExceptionHandlingMiddleware");
        
        return ValueTask.FromResult(false);
    }
}

Program.cs配置

builder.Services.AddExceptionHandler<ExceptionHandlingMiddleware>();
app.UseExceptionHandler();

核心原因

当请求发生异常进入IExceptionHandler的TryHandleAsync方法时,当前请求的Scoped服务范围(Scope)已经开始销毁:

  • 如果Serilog的SQL Sink依赖Scoped的DbContext,此时该上下文已被释放,无法执行数据库写入
  • 若请求存在未提交的事务,异常会触发事务回滚,若日志写入被包含在该事务中,也会被回滚
  • HttpContext的状态已进入请求收尾阶段,部分依赖请求上下文的服务已不可用

解决方案

方案1:配置Serilog SQL Sink使用独立连接(不依赖Scoped DbContext)

确保Serilog直接使用连接字符串初始化SQL Sink,而非依赖注入的DbContext,这样日志写入不依赖请求Scope。

修改Serilog配置示例:

Log.Logger = new LoggerConfiguration()
    .WriteTo.Console()
    .WriteTo.File("logs/log-.txt", rollingInterval: RollingInterval.Day)
    .WriteTo.MSSqlServer(
        connectionString: "Your_SQL_Server_Connection_String",
        sinkOptions: new MSSqlServerSinkOptions { TableName = "Logs" })
    .CreateLogger();

方案2:在TryHandleAsync中创建新的服务Scope

手动创建独立的Scope,在新Scope内执行日志写入,避免依赖已销毁的请求Scope:

修改ExceptionHandlingMiddleware代码:

public class ExceptionHandlingMiddleware : IExceptionHandler
{
    private readonly ILogger<ExceptionHandlingMiddleware> _logger;
    private readonly IServiceProvider _serviceProvider;

    public ExceptionHandlingMiddleware(ILogger<ExceptionHandlingMiddleware> logger, IServiceProvider serviceProvider)
    {
        _logger = logger;
        _serviceProvider = serviceProvider;
        
        _logger.LogInformation("1-ExceptionHandlingMiddleware");
    }

    public async ValueTask<bool> TryHandleAsync(HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        // 创建新的服务Scope
        using var scope = _serviceProvider.CreateScope();
        var scopedLogger = scope.ServiceProvider.GetRequiredService<ILogger<ExceptionHandlingMiddleware>>();
        
        // 使用新Scope的Logger写入日志
        scopedLogger.LogInformation("2-ExceptionHandlingMiddleware");
        
        return false;
    }
}

方案3:确保日志操作脱离请求事务

如果日志写入被包含在请求事务中,异常回滚会导致日志丢失。可以:

  • 配置Serilog SQL Sink使用独立事务,不参与请求的事务
  • 手动开启新的数据库连接执行日志写入,避免复用请求的连接

验证步骤

  1. 修改配置或代码后,触发异常进入TryHandleAsync
  2. 检查SQL Server的日志表,确认日志已正常写入
  3. 同时验证文件和控制台日志仍正常输出

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 07:16:14