Audit.Net更新时插入空记录并触发递归内存溢出问题排查
问题原因与解决方案
从你的描述和代码来看,这个递归审计导致内存溢出的问题,核心原因是AuditLog实体本身被纳入了审计范围,触发了无限递归的审计循环,具体分析和解决方法如下:
1. 核心问题:AuditLog的递归审计
你使用的AuditDbContext会自动跟踪并审计所有DbSet中实体的变更。当你保存一条AuditLog记录时,DbContext会检测到这个新增/修改操作,再次触发Audit.Net的审计流程,生成新的AuditLog记录——这个过程会无限循环下去,每次生成的AuditData JSON会包含更多的嵌套审计信息,最终耗尽内存抛出OutOfMemoryException。
另外,你重写的Entry<T>方法也存在隐患:
public new DbEntityEntry<T> Entry<T>(T entity) where T : class { return (new PContext().Entry(entity) as DbEntityEntry<T>); }
每次调用Entry都新建一个PContext实例,会导致实体跟踪上下文不一致,不仅可能加剧递归问题,还会引发其他数据操作的异常。
2. 解决方案
方案一:排除AuditLog实体的审计
你需要明确告诉Audit.Net不要审计AuditLog实体的变更,有两种方式:
- 方式1:使用特性标记
在AuditLog类上添加[AuditIgnore]特性:
[AuditIgnore] public class AuditLog { // 你的实体属性 }
- 方式2:在配置中忽略实体
修改Startup中的Audit配置,添加IgnoreEntity<AuditLog>():
Audit.Core.Configuration.Setup() .UseEntityFramework(_ => _ .AuditTypeMapper(t => typeof(AuditLog)) .AuditEntityAction<AuditLog>((ev, entry, entity) => { entity.AuditData = entry.ToJson(); entity.AuditDate = DateTime.Now; entity.AuditUser = Environment.UserName; entity.AuditUsername = HttpContext.Current.User.Identity.Name; }) .IgnoreMatchedProperties(true) .IgnoreEntity<AuditLog>()); // 添加这一行
方案二:修复重写的Entry方法
将Entry<T>方法改为使用基类的实现,避免新建上下文:
public new DbEntityEntry<T> Entry<T>(T entity) where T : class { return base.Entry(entity); }
如果不需要自定义Entry逻辑,甚至可以直接删除这个重写方法,使用AuditDbContext的默认实现即可。
3. 验证修复
完成上述修改后,更新实体时Audit.Net只会生成一条对应的AuditLog记录,不会再触发递归,内存溢出问题也会随之解决。
内容的提问来源于stack exchange,提问作者nightowl
相关产品推荐
相关产品推荐

