【问题标题】:ASP.NET Core API - Second operation is started on Db context before a previous operation completedASP.NET Core API - 在前一个操作完成之前在 Db 上下文上启动第二个操作
【发布时间】:2022-09-27 15:15:56
【问题描述】:

我在 ASP.NET 核心应用程序上收到以下异常:

\"在配置时尝试使用上下文。不能在 \'OnConfiguring\' 中使用 DbContext 实例,因为此时仍在配置它。如果在此上下文上启动第二个操作,则可能会发生这种情况在上一个操作完成之前。不保证任何实例成员都是线程安全的。\"

我知道它产生该错误的原因。我的应用程序中的多个线程同时尝试初始化 DBContext,即从前端接收多个请求都访问相同的方法

public async Task<IEnumerable<T>> QueryAsync<T>(string sqlStmt, Parameter[] inputParameters = null)
    {
        if (inputParameters is null)
            return await Database.GetDbConnection().QueryAsync<T>(sqlStmt);
        paramsList = new DynamicParameters();
        paramsList.AddParamater(inputParameters);
        return await Database.GetDbConnection().QueryAsync<T>(sqlStmt, paramsList);  <--Here the exception is raised
    }

如果想知道 \'Database\' 指的是什么,那么它是 EFCore 6.0.9 的 DbContext 类中的 DatabaseFacade 类型属性;这是代码:

namespace Microsoft.EntityFrameworkCore{
public class DbContext :
    IInfrastructure<IServiceProvider>,
    IDbContextDependencies,
    IDbSetCache,
    IDbContextPoolable
{
    private readonly DbContextOptions _options;

    private IDictionary<(Type Type, string? Name), object>? _sets;
    private IDbContextServices? _contextServices;
    private IDbContextDependencies? _dbContextDependencies;
    private DatabaseFacade? _database;

/// <summary>
    ///     Provides access to database related information and operations for this context.
    /// </summary>
    public virtual DatabaseFacade Database
    {
        get
        {
            CheckDisposed();

            return _database ??= new DatabaseFacade(this);
        }
    }
 }}

我在 Startup.cs 的 ConfigureServices 方法中注入 DBContext,因此我无法为每个线程创建多个 DBContext。

此外,在配置上下文时,DBContext 的服务生命周期设置为瞬态:

services.AddDbContextFactory<MyQueryDbContext>(options => options.UseSqlServer(MyQuery, sqlServerOptions => sqlServerOptions.CommandTimeout(databaseTimeout)), ServiceLifetime.Transient);

MyQueryDbContext 看起来像这样:

public class MyQueryDbContext  : MyDbCtx<MyQueryDbContext>, IMyQuery
{
    public MyQueryDbContext(DbContextOptions<MyQueryDbContext> model) : base(model)
    {
    }
}

这是 MyDbCtx:

public class MyDbCtx<TContext> : DbContext
{
    public MyDbCtx(DbContextOptions<TContext> model) : base(model)
    {
    }
}

因此,我没有显式覆盖 OnConfiguring 方法,因为我从外部提供了配置详细信息

我可以使该异步方法同步运行,但我还有哪些其他选择?

  • Database 来自哪里以及如何使用?您发布的代码没有显示任何尝试从多个线程使用 DbContext。它显示了在 EF Core 之上使用 Dapper 的尝试,而不是仅仅打开一个连接。那不会产生你得到的错误。使此方法同步惯于修复使用 DbContext 作为 DbConnection 的错误
  • 请发布您的OnConfiguring 代码以及您如何称呼QueryAsync。此代码是对 EF Core 的误用 - DbContext 不是数据库连接,它是一个短暂的工作单元,跟踪和持久化在单身的业务/应用程序“事务”。它并不意味着从多个线程中使用,因为它不需要。它也不是使用 SqlConnection 的替代方法
  • 很多时候,这个错误是循环的结果,在第一个迭代完成之前执行下一次迭代。调试一下看看是不是这样。

标签: c# entity-framework asp.net-core dependency-injection


【解决方案1】:

在启动时将包含异常引发方法的类型的服务添加为“作用域”后解决。错过了它被添加为单例

【讨论】:

    猜你喜欢
    • 2018-11-07
    • 1970-01-01
    • 2020-09-30
    • 2020-11-06
    • 1970-01-01
    • 2022-01-01
    • 1970-01-01
    • 2018-07-23
    • 1970-01-01
    相关资源
    最近更新 更多