.NET 5 EF Core SaveChangesAsync 因错误而挂起 [英] .NET 5 EF Core SaveChangesAsync hangs on errors

查看:26
本文介绍了.NET 5 EF Core SaveChangesAsync 因错误而挂起的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Despite there are many results for this question none have really given me a clear answer.

每次我尝试通过 AddAsync 和 SaveChangesAsync 方法插入错误数据(例如重复的主键)时,我都会看到此日志:执行 DbCommand 失败(15 毫秒)

Every time I try to insert faulty data such as a duplicate primary key, via the AddAsync and SaveChangesAsync methods, I see this log: Failed executing DbCommand (15ms)

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

I also see the error on the SQL PROFILER and it very clear it's a primary key conflict. In these cases the SaveChangesAsync does not throw any error! It just hangs indefinitely causing a memory leak and eventually the app crashes. I tried wrapping the savechanges with a try catch to no avail, and even added a cancellation token to auto cancel after 2 seconds and even that did not stop the hang. The result is always a never ending HTTP request that never returns a response to the client. *I also tried running the savechangesasync without the configure await and the result is the same.

上下文和存储库的 DI:

DI for context and repository:

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

services.AddScoped<IRepository, EfRepository>();

控制器方法:

[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 是调用者:

The addasync is the caller:

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();
    }
}

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

I fixed the issue by checking there are no violations, but this does not solve the root problem that currently it is impossible for me to log these errors and if this happens again somewhere it will destroy the website.

根据请求:整个上下文类:

As per request: The entire context 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;
    }
}

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

*The lifetime of the context probably has nothing to do with it, I reproduced the issue with every lifetime.

这是调用堆栈:

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

*More information: The hang occurs also when saving with the non Async method. When manually throwing an error in the savechanges it bubbles up correctly. In another project that shares the same DLLs, the SaveChanges throws an error that bubbles up correctly, also in Async methods.

推荐答案

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

I have finally found the Issue!! I sat down and just started removing code one line at a time until I found the culprit!

.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 has been giving be the hard time all along. There were no errors pointing in the direction that something is wrong with the logging because all the logs work. So I just removed features one after another until when I removed this the hanging stopped and exceptions started to bubble up.

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

Thank you for every one who commented and tried to help me, it is much appreciated!

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

I ended up ditching Serilog and using Seq directly with ILogging extension and everything now works fine!

这篇关于.NET 5 EF Core SaveChangesAsync 因错误而挂起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆