【问题标题】:Correctly using of dependency injected DbContext to query Database正确使用依赖注入的 DbContext 查询数据库
【发布时间】:2019-08-01 16:52:40
【问题描述】:

我已经使用(我认为是正确的)设置了自己的上下文:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContextPool<JobTrackingContext>(options => options.UseNpgsql(connection));
    services.AddScoped<IJobRepository, JobRepository>();
}

然后我定义我的JobTrackingContext如下:

public JobTrackingContext(DbContextOptions<JobTrackingContext> options)
            : base(options)
{
    public DbSet<Job> Jobs { get; set; }
}

现在我可以定义一个存储库来实际创建/编辑/删除作业:

 public class JobRepository : GenericRepository<Job, long>, IJobRepository
{
        private Job currentJob;
        public JobRepository(JobTrackingContext jobTrackingContext, JobTrackingSettings settings)
        : base(jobTrackingContext)
    {
        _settings = settings;
    }
        public async Task StartSync(JobType jobType, JobTriggerType jobTriggerType)
        {
            var tempJob = new Job(jobType, jobTriggerType);
            await _dbContext.Jobs.AddAsync(tempJob);
            await _dbContext.SaveChangesAsync();
        }
}

所有这些代码都通过对该 API 的 Post-request 实例化:

public async void Post()
{
    _logger.LogDebug("Going to start account sync");
    await _jobRepository.StartSync(JobType.ZRequestSync, JobTriggerType.Scheduled);
    try
    {
        await _sync.StartAsync();
        await _jobRepository.ChangeSyncStatus(JobStatusType.Finished);
    }
    catch (Exception e)
    {
        _logger.LogError(e, "Error occured during sync :(");
        await _jobRepository.ChangeSyncStatus(JobStatusType.Failed);
    }
}

然而,当我这样做时,我得到一个异常消息Reset() called on connector with state Connecting。我不明白这是从哪里来的。 当我不使用注入版本,而是这样做时:

using (var c = new JobTrackingContext())
{
    var job = new Job(jobType, jobTriggerType)
    await c.Jobs.AddAsync(job);
    await c.SaveChangesAsync();
}

似乎一切正常。似乎上下文被处理得太早了。但是我怎样才能防止这种情况和/或我错过了什么?

完整的堆栈跟踪:

    System.ObjectDisposedException
  HResult=0x80131622
  Message=Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
  Source=Microsoft.EntityFrameworkCore
  StackTrace:
   at Microsoft.EntityFrameworkCore.DbContext.CheckDisposed()
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.<SaveChangesAsync>d__52.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()
   at ZShared.JobRepository.<StartSync>d__4.MoveNext() in C:\Users\richa\Documents\Codes\Company\Product\Shared\Folder\JobRepository.cs:line 38
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ZAccountSyncService.AccountSyncController.<Post>d__4.MoveNext() in C:\Users\richa\Documents\Code\Company\Product\SubProduct\AccountSyncController.cs:line 32
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()

【问题讨论】:

  • _dbContext 在您的JobRepository 代码示例中来自哪里?似乎您在示例中有整个类,但既没有构造函数,也没有名为 _dbContext...
  • 保存在超类中,我现在做的更清楚了
  • 你试过.AddDbContext而不是.AddDbContextPool吗?它有效吗?你的生命周期是多少?它是一个什么样的应用程序? ASP.NET (Core) 还是其他的?此外:您的最后一个代码示例可能会起作用,因为它在调用 .AddAsync 方法时缺少 await。在那里添加被遗忘的await 是否有效?
  • 是的,我尝试将其更改为.AddDbContext,但遗憾的是这并不能解决问题。生命周期范围是什么?我的JobRepository 是作用域的,就像我的大多数课程一样。 JobTrackingContext 也是如此。这是一个 ASP.NETCORE 应用程序,是的,添加 await 不会破坏我的其他示例。
  • ("scoped" 意味着您在一个范围内为每个范围内的服务获取一个实例。范围多长时间取决于您 - 在 ASP.NET Core 中,默认情况下会为每个 Web 请求创建一个范围。 ) 你什么时候得到异常?打电话时SaveChangesAsync?你能提供整个堆栈跟踪吗?

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


【解决方案1】:

问题的要点是您的AccountSyncController.Post 方法的声明。你有async void Post() 而不是async Task Post()

当没有任务时,请求没有等待,在方法@​​987654324@的调用完成之前结束。随着请求的结束,生命周期的结束也随之而来。在生命周期范围结束时,所有具有范围生命周期的实例都会被释放。因此,在您调用 SaveChanges 方法之前,您的上下文已被处理。这就是您的异常的原因。

【讨论】:

  • 感谢您帮助解决此问题并投入与您一样多的时间
猜你喜欢
  • 2020-05-11
  • 2018-05-06
  • 2020-10-06
  • 1970-01-01
  • 2021-10-23
  • 2012-05-27
  • 1970-01-01
  • 2021-02-09
相关资源
最近更新 更多