繁体   English   中英

.NET 5 EF Core SaveChangesAsync 因错误而挂起

[英].NET 5 EF Core SaveChangesAsync hangs on errors

尽管这个问题有很多结果,但没有一个真正给我一个明确的答案。

每次我尝试通过 AddAsync 和 SaveChangesAsync 方法插入错误数据(例如重复的主键)时,我都会看到以下日志:Failed execution DbCommand (15ms)

我还在 SQL PROFILER 上看到了错误,很明显这是主键冲突。 在这些情况下,SaveChangesAsync 不会引发任何错误。 它只是无限期挂起,导致 memory 泄漏,最终应用程序崩溃,我尝试用 try catch 包装 savechanges 无济于事。 甚至添加了一个取消令牌以在 2 秒后自动取消,即使这样也没有停止挂起。 结果始终是永不结束的 HTTP 请求,该请求永远不会向客户端返回响应。 *我也尝试在没有配置等待的情况下运行 savechangesasync,结果是一样的。

用于上下文和存储库的 DI:

        services.AddDbContext<SalesDBContext>(o => 
            o.UseSqlServer(appSettings.ConnectionString)
            .EnableDetailedErrors(true)
            .EnableSensitiveDataLogging()
        , ServiceLifetime.Scoped);

services.AddScoped<IRepository, EfRepository>();

Controller 方法:

[HttpPost]
public async Task<IActionResult> Post([FromBody] SomeRequest request)
{
    if (ModelState.IsValid)
    {
        var data = await _service.AddAsync(request);
        return Ok(data);
    }
    return BadRequest(ModelState.Values);
}

addasync 是调用者:

public class EfRepository : IRepository
{
    private readonly SalesDBContext _dbContext;

    public EfRepository(SalesDBContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task<int> AddAsync<T>(T entity) where T : Entity
    {
        _dbContext.Set<T>().Add(entity);
        return await _dbContext.SaveChangesAsync();
    }
}

我通过检查没有违规来解决问题,但这并不能解决根本问题,即目前我无法记录这些错误,如果这种情况再次发生在某个地方,它将破坏网站。

根据要求:整个上下文 class:

    public class SalesDBContext : DbContext
{
    public DbSet<Entity> Entities { get; set; }


    public SalesDBContext(DbContextOptions<SalesDBContext> options) : base(options)
    {

    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.OnConfiguring(optionsBuilder);
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.ApplyConfigurationsFromAssembly(System.Reflection.Assembly.GetExecutingAssembly());

        foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
        {
            relationship.DeleteBehavior = DeleteBehavior.Restrict;
        }
    }
    //This is the savechanges being called.
    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        int result = await base.SaveChangesAsync(cancellationToken); 
        //Hangs here on primary key conflict error
        return result;
    }
}

*上下文的生命周期可能与它无关,我在每个生命周期都重现了这个问题。

这是调用堆栈: 调用堆栈

*更多信息:使用非异步方法保存时也会发生挂起。 当在 savechanges 中手动抛出错误时,它会正确冒泡。 在另一个共享相同 DLL 的项目中,SaveChanges 会抛出一个正确冒泡的错误,在 Async 方法中也是如此。

我终于找到问题了!! 我坐下来,开始一次一行地删除代码,直到找到罪魁祸首!

.UseSerilog((hostingContext, loggerConfiguration) => {
    loggerConfiguration
    .ReadFrom.Configuration(hostingContext.Configuration)
    .Enrich.FromLogContext()
    .Enrich.WithProperty("ApplicationName", typeof(Program).Assembly.GetName().Name)
    .Enrich.WithProperty("Environment", hostingContext.HostingEnvironment);
#if DEBUG
    loggerConfiguration.Enrich.WithProperty("DebuggerAttached", Debugger.IsAttached);
#endif
});

Serilog 一直以来都是艰难的时期。 没有错误指出日志记录有问题,因为所有日志都有效。 所以我只是一个接一个地删除了功能,直到当我删除这个时,挂起停止并且异常开始冒泡。

感谢每一位评论并试图帮助我的人,非常感谢!

我最终放弃了 Serilog,直接将 Seq 与 ILogging 扩展一起使用,现在一切正常!

在评论中,您说您将数据库上下文注入为瞬态。 我建议将其作为作用域注入,这将确保您在整个数据流中的每个请求都使用“相同”的 dbcontext。

使用不同的 dbcontext,就像使用瞬态生命周期一样,在对数据访问流的同一请求中的不同消费者中可能会导致奇怪的行为,例如

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM