如何在主线程处理后再次获取 DBContext?
How to get DBContext again after the Main Thread disposes?
网芯。我正在使用 EF 核心、工作单元和存储库模式。在我的代码中,我使用 await Task.Delay(150) 释放我的主线程;然后我试图获取 DB 上下文,但异常显示 Dbcontext 已处理。那么有什么办法可以在主线程处理后再次获取 DBContext 吗?下面是我的代码片段,
services.AddDbContext<MyContext>(options =>
options.UseSqlServer(this.Configuration["AzureSQLConnectionString"]));
services.AddScoped<IUnitOfWork, UnitOfWork>();
下面是我的方法
public Class MyTestBusinessLogic : IMyTestBusinessLogic
{
public MyTestBusinessLogic(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork));
MyTestRepository= UnitOfWork.GetRepository<MyTest>();
}
private IDbRepository<MyTest> MyTestRepository{ get; set; }
public async Task MyMethod()
{
await MyTestRepository.GetFirstOrDefaultAsync(x => x.Id == Id); // works here
await Task.Delay(150);
// here after my context disposes
await MyTestRepository.GetFirstOrDefaultAsync(x => x.Id == Id); //this wont work and It will throw error inside GetFirstOrDefaultAsync method.
}
}
GetFirstOrDefaultAsync 方法
public class DbRepository<T> : BaseRepository<T>, IDbRepository<T> where T : class
{
private readonly DbContext dbContext;
private readonly DbSet<T> dbSet;
public DbRepository(DbContext dbContext)
{
this.dbContext = dbContext;
this.dbSet = dbContext?.Set<T>();
}
public async Task<T> GetFirstOrDefaultAsync(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, params Expression<Func<T, object>>[] includes)
{
IQueryable<T> query = this.dbSet; // throws exception saying cannot use disposed object
foreach (Expression<Func<T, object>> include in includes)
{
query = query.Include(include);
}
if (filter != null)
{
query = query.Where(filter);
}
if (orderBy != null)
{
query = orderBy(query);
}
return await query.FirstOrDefaultAsync().ConfigureAwait(false);
}
}
有人可以帮我解决这个问题吗?任何帮助,将不胜感激。谢谢
我假设你 运行 MyMethod
没有 await
ing 它。因此,当主线程完成执行时,它将销毁 dbcontext
或从 DI
.
注入的任何 scoped
对象
为了满足您的要求,您可以使用 IServiceScopeFactory
,它是 singleton
对象并由 .net core
框架添加。使用它,您可以使用 serviceScopeFactory.CreateScope()
创建 scope
并使用 scope.ServiceProvider.GetRequiredService<MyDbContext>();
.
创建所需 dependencies
的新实例
所以在这种情况下你可以像下面这样使用。请参考评论以了解。我不知道您的应用程序的确切结构,所以我将 IServiceScopeFactory
添加到您的 MyTest
中以获得 example/test。但是根据您的代码,您可以将其移动到其他地方,我猜是 UnitOfWork
.
public Class MyTestBusinessLogic : IMyTestBusinessLogic
{
// Add serviceScopeFactory
private readonly IServiceScopeFactory serviceScopeFactory;
// Inject IServiceScopeFactory and assign to class object.
public MyTestBusinessLogic(IServiceScopeFactory serviceScopeFactory)
{
this.serviceScopeFactory = serviceScopeFactory;
// Create scope with IServiceScopeFactory.CreateScope()
var scope = serviceScopeFactory.CreateScope();
// GetRequiredService unitOfWork
UnitOfWork = scope.ServiceProvider.GetRequiredService<IUnitOfWork>();
// UnitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork));
MyTestRepository= UnitOfWork.GetRepository<MyTest>();
}
private IDbRepository<MyTest> MyTestRepository{ get; set; }
public async Task MyMethod()
{
await MyTestRepository.GetFirstOrDefaultAsync(x => x.Id == Id); // works here
await Task.Delay(150);
// here after my context disposes
await MyTestRepository.GetFirstOrDefaultAsync(x => x.Id == Id); //this wont work and It will throw error inside GetFirstOrDefaultAsync method.
}
}
I am calling without await
这是你的问题。 So-called“即发即弃”在 ASP.NET 上是危险的,并且仅在 代码 运行 与否 时才适用.在您的情况下,由于您需要 运行 的代码,因此省略 await
是不合适的。
正确的解决方法是用await
调用MyMethod
。
如果你绝对必须 return早,那么next-best解决方案是引入一个可靠的队列(例如,Azure Queue / Amazon SMS)以及处理该队列上消息的后台处理器(例如,Azure Function / Amazon Lambda / .NET Core BackgroundService)。一旦你有了这些,当你遇到需要提前 return 并稍后完成工作的情况时,该代码会将一条消息放入队列,然后 return 一个结果。当后台处理器从队列中检索到消息时,它就会开始工作。
网芯。我正在使用 EF 核心、工作单元和存储库模式。在我的代码中,我使用 await Task.Delay(150) 释放我的主线程;然后我试图获取 DB 上下文,但异常显示 Dbcontext 已处理。那么有什么办法可以在主线程处理后再次获取 DBContext 吗?下面是我的代码片段,
services.AddDbContext<MyContext>(options =>
options.UseSqlServer(this.Configuration["AzureSQLConnectionString"]));
services.AddScoped<IUnitOfWork, UnitOfWork>();
下面是我的方法
public Class MyTestBusinessLogic : IMyTestBusinessLogic
{
public MyTestBusinessLogic(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork));
MyTestRepository= UnitOfWork.GetRepository<MyTest>();
}
private IDbRepository<MyTest> MyTestRepository{ get; set; }
public async Task MyMethod()
{
await MyTestRepository.GetFirstOrDefaultAsync(x => x.Id == Id); // works here
await Task.Delay(150);
// here after my context disposes
await MyTestRepository.GetFirstOrDefaultAsync(x => x.Id == Id); //this wont work and It will throw error inside GetFirstOrDefaultAsync method.
}
}
GetFirstOrDefaultAsync 方法
public class DbRepository<T> : BaseRepository<T>, IDbRepository<T> where T : class
{
private readonly DbContext dbContext;
private readonly DbSet<T> dbSet;
public DbRepository(DbContext dbContext)
{
this.dbContext = dbContext;
this.dbSet = dbContext?.Set<T>();
}
public async Task<T> GetFirstOrDefaultAsync(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, params Expression<Func<T, object>>[] includes)
{
IQueryable<T> query = this.dbSet; // throws exception saying cannot use disposed object
foreach (Expression<Func<T, object>> include in includes)
{
query = query.Include(include);
}
if (filter != null)
{
query = query.Where(filter);
}
if (orderBy != null)
{
query = orderBy(query);
}
return await query.FirstOrDefaultAsync().ConfigureAwait(false);
}
}
有人可以帮我解决这个问题吗?任何帮助,将不胜感激。谢谢
我假设你 运行 MyMethod
没有 await
ing 它。因此,当主线程完成执行时,它将销毁 dbcontext
或从 DI
.
scoped
对象
为了满足您的要求,您可以使用 IServiceScopeFactory
,它是 singleton
对象并由 .net core
框架添加。使用它,您可以使用 serviceScopeFactory.CreateScope()
创建 scope
并使用 scope.ServiceProvider.GetRequiredService<MyDbContext>();
.
dependencies
的新实例
所以在这种情况下你可以像下面这样使用。请参考评论以了解。我不知道您的应用程序的确切结构,所以我将 IServiceScopeFactory
添加到您的 MyTest
中以获得 example/test。但是根据您的代码,您可以将其移动到其他地方,我猜是 UnitOfWork
.
public Class MyTestBusinessLogic : IMyTestBusinessLogic
{
// Add serviceScopeFactory
private readonly IServiceScopeFactory serviceScopeFactory;
// Inject IServiceScopeFactory and assign to class object.
public MyTestBusinessLogic(IServiceScopeFactory serviceScopeFactory)
{
this.serviceScopeFactory = serviceScopeFactory;
// Create scope with IServiceScopeFactory.CreateScope()
var scope = serviceScopeFactory.CreateScope();
// GetRequiredService unitOfWork
UnitOfWork = scope.ServiceProvider.GetRequiredService<IUnitOfWork>();
// UnitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork));
MyTestRepository= UnitOfWork.GetRepository<MyTest>();
}
private IDbRepository<MyTest> MyTestRepository{ get; set; }
public async Task MyMethod()
{
await MyTestRepository.GetFirstOrDefaultAsync(x => x.Id == Id); // works here
await Task.Delay(150);
// here after my context disposes
await MyTestRepository.GetFirstOrDefaultAsync(x => x.Id == Id); //this wont work and It will throw error inside GetFirstOrDefaultAsync method.
}
}
I am calling without await
这是你的问题。 So-called“即发即弃”在 ASP.NET 上是危险的,并且仅在 代码 运行 与否 时才适用.在您的情况下,由于您需要 运行 的代码,因此省略 await
是不合适的。
正确的解决方法是用await
调用MyMethod
。
如果你绝对必须 return早,那么next-best解决方案是引入一个可靠的队列(例如,Azure Queue / Amazon SMS)以及处理该队列上消息的后台处理器(例如,Azure Function / Amazon Lambda / .NET Core BackgroundService)。一旦你有了这些,当你遇到需要提前 return 并稍后完成工作的情况时,该代码会将一条消息放入队列,然后 return 一个结果。当后台处理器从队列中检索到消息时,它就会开始工作。