使用依赖注入时,如何修复“在前一个操作完成之前在此上下文中启动的第二个操作......”?
Posted
技术标签:
【中文标题】使用依赖注入时,如何修复“在前一个操作完成之前在此上下文中启动的第二个操作......”?【英文标题】:How to fix 'A second operation started on this context before a previous operation completed...' when working with dependency injection? 【发布时间】:2018-03-05 19:54:33 【问题描述】:从数据库读取数据时出现此错误:
在前一个操作之前在此上下文上启动了第二个操作 完全的。不保证任何实例成员都是线程安全的。
我有以下 ApplicationContext.cs:
public class ApplicationContext : Microsoft.EntityFrameworkCore.DbContext
public ApplicationContext(DbContextOptions<ApplicationContext> options)
: base(options)
public DbSet<MyClass> MyClasses get; set;
以下ApplicationContextFactory.cs
public class ApplicationContextFactory : IDesignTimeDbContextFactory<ApplicationContext>
public ApplicationContext CreateDbContext(string[] args)
var builder = new DbContextOptionsBuilder<ApplicationContext>();
var connection = "myConnectionString";
builder.UseSqlServer(connection);
return new ApplicationContext(builder.Options);
以下 ServiceLoader.cs(我在其中声明 DI):
public static class ServiceLoader
public static void ConfigureServices(IServiceCollection services)
services.AddSingleton<IRepository, Repository>();
var connection = "myConnectionString";
services.AddDbContext<ApplicationContext>(options => options.UseSqlServer(connection));
最后是引发异常的以下存储库:
public class Repository : IRepository
private ApplicationContext _db;
public Repository (ApplicationContext db)
_db = db;
public List<MyClass> Get()
_db.MyClasses.ToList();
我也尝试将 Repository 声明为 Transient 而不是 Singleton,但抛出了类似的错误
'在配置时尝试使用上下文。 DbContext 实例不能在 OnConfiguring 中使用,因为此时它仍在配置中。如果在前一个操作完成之前对此上下文启动了第二个操作,则可能会发生这种情况。不保证任何实例成员都是线程安全的。'
关于如何解决这个问题的任何想法?谢谢!
【问题讨论】:
您应该在Repository
单例之前声明上下文。另请注意,隐藏实体框架的大多数存储库实现都是浪费开发时间并给出 0 值。您应该对在存储库中隐藏存储库有一个很好的解释
还要注意这个模型很奇怪:Repository
(单例)依赖于一个临时服务(DbContext
)
另外,Repository
正在使用Entity Framework Core
,它以sync
的方式允许完整的async
方法,从而不必要地阻塞线程。
如果问题得到解决,您应该发布答案
@CamiloTerevinto 正如我所说的,它也是一种补充大查询的 DRY 原则的方法。实际上,当我不得不替换系统中广泛使用的一种存储库方法的实现以使用 StoredProcedure 而不是 EF 查询(例如)时,我遇到了很多情况。如果这些查询分散在整个系统中会发生什么? :)
【参考方案1】:
就我而言,我发现以下信息很有帮助:
https://docs.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext
并在启动时使用重载的 AddDbContext 方法将我的 Db 上下文的生命周期范围更改为瞬态:
services.AddDbContext<MyAppDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection"));
, ServiceLifetime.Transient);
【讨论】:
【参考方案2】:您可以在 Get() 函数周围包裹一个异步任务并等待您的结果:
public async Task<List<MyClass>> Get()
return await _db.MyClasses.ToListAsync();
【讨论】:
【参考方案3】:我写了一个使用队列的解决方案。它仍然是单线程的,但你可以从不同的线程调用它。
public class ThreadSafeDataContext
private Thread databaseThread;
private Queue<PendingQuery> pendingQueries = new Queue<PendingQuery>();
private DatabaseContext db = new DatabaseContext();
private bool running = true;
public ThreadSafeDataContext()
databaseThread = new Thread(new ThreadStart(DoWork));
databaseThread.Start();
public void StopService()
running = false;
private void DoWork()
while(running)
if (pendingQueries.Count > 0)
// Get and run query
PendingQuery query = pendingQueries.Dequeue();
query.result = query.action(db);
query.isFinished = true;
else
Thread.Sleep(1); // Waiting for queries
public T1 Query<T1>(Func<DatabaseContext, T1> action)
Func<DatabaseContext, object> a = (DatabaseContext db) => action(db);
PendingQuery query = new PendingQuery(a);
pendingQueries.Enqueue(query);
while (!query.isFinished)
Thread.Sleep(1); // Wait until query is finished
return (T1)query.result;
class PendingQuery
public Func<DatabaseContext, object> action;
public bool isFinished;
public object result;
public PendingQuery(Func<DatabaseContext, object> action)
this.action = action;
然后您可以使用以下命令从不同线程运行查询:
TeamMembers teamMembers = threadSafeDb.Query((DatabaseContext c) => c.team.ToArray())
【讨论】:
以上是关于使用依赖注入时,如何修复“在前一个操作完成之前在此上下文中启动的第二个操作......”?的主要内容,如果未能解决你的问题,请参考以下文章
Entity Framework Core:在前一个操作完成之前在此上下文上启动了第二个操作
Blazor:在前一个操作完成之前在此上下文上启动了第二个操作
asp.net core 在前一个操作完成之前在此上下文上启动了第二个操作