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

.NET EF Core 3.1使用NLog :format=@更新大模型遇DB错误时内存泄漏

解决EF Core结合NLog ${exception:format=@} 导致SaveChangesAsync内存耗尽的问题

问题场景

执行以下代码时,一旦触发数据库错误「String or binary data would be truncated」(字符串/二进制数据过长,无法存入对应字段),SaveChangesAsync会直接挂起,内存持续上涨直到耗尽:

context.Update(myBigObject);
await context.SaveChangesAsync(); // 此处出现异常后挂起

这个问题只会在NLog配置使用${exception:format=@}时触发——改用${exception:format=toString}能临时解决,但会丢失内部异常的详细信息。另外该问题在Serilog中也会出现,推测根源和EF Core有关。


不用改NLog格式的解决方案

方案1:捕获异常时手动清理EF Core的异常引用

在捕获DbUpdateException时,手动创建一个仅包含关键信息的干净异常对象,避免EF Core内部的循环引用或大对象被NLog深度序列化:

try
{
    await context.SaveChangesAsync();
}
catch (DbUpdateException ex)
{
    // 只保留异常消息和内部异常,剥离EF Core上下文引用
    var cleanException = new Exception(ex.Message, ex.InnerException);
    logger.Error(cleanException, "数据保存失败");
    // 要继续抛出异常的话,扔原始的就行
    throw;
}

方案2:给NLog加自定义异常渲染器

针对DbUpdateException做特殊处理,其他异常依然用@格式完整序列化:

  1. 写一个自定义渲染器类:
public class CleanDbUpdateExceptionRenderer : ExceptionLayoutRenderer
{
    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
        if (logEvent.Exception is DbUpdateException dbEx)
        {
            // 拼接包含内部异常的完整信息,避免序列化EF内部对象
            var logContent = $"[{nameof(DbUpdateException)}] {dbEx.Message}\n";
            if (dbEx.InnerException != null)
            {
                logContent += $"内部异常: {dbEx.InnerException.Message}\n";
            }
            if (!string.IsNullOrWhiteSpace(dbEx.StackTrace))
            {
                logContent += $"堆栈信息:\n{dbEx.StackTrace}";
            }
            builder.Append(logContent);
        }
        else
        {
            // 非DbUpdateException用默认的@格式
            base.Append(builder, logEvent);
        }
    }
}
  1. 在NLog配置里注册并使用这个渲染器:
<nlog>
    <extensions>
        <add assembly="你的程序集名称"/>
    </extensions>
    <targets>
        <target name="fileLog" type="File" fileName="logs/${shortdate}.log">
            <layout>${longdate} ${level} ${message} ${cleanDbUpdateException:format=@}</layout>
        </target>
    </targets>
    <rules>
        <logger name="*" minlevel="Error" writeTo="fileLog"/>
    </rules>
</nlog>

方案3:限制EF Core的敏感日志输出

在DbContext配置里禁用敏感数据日志,减少EF Core异常中携带的数据量,从根源降低序列化负担:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .UseSqlServer("你的连接字符串")
        .EnableSensitiveDataLogging(false); // 关闭敏感数据日志,减少异常里的冗余数据
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 22:25:17