【问题标题】:Access DbContext service from background task从后台任务访问 DbContext 服务
【发布时间】:2018-07-28 15:12:01
【问题描述】:

因此,ASP.NET Core 应用程序内置了依赖注入。借助 Entity Framework Core,您可以轻松地从控制器操作方法中获取作用域 DbContext 实例。

但这仅限于控制器操作。如果您需要从一个将通过其他方式(如 WebSocket)与浏览器中的视图进行通信的操作启动一个长时间运行的后台任务,那么您突然之间什么都没有了。后台任务不能使用操作的 DbContext,因为它在操作返回时被限定并释放。

一种简单的方法是使用人们所说的服务定位器。这是一些 IServiceProvider 的静态副本,供以后访问和服务解析。 (ASP.NET Core 2.1 可能需要一种不同的方法,因为我已经阅读了in this comment。)但是无论我在哪里看,这都被描述为反模式。它使测试变得更加困难并混淆了依赖关系。好的。

那么对于这种情况,推荐的解决方案是什么?我在不知名的地方。甚至可以从调度程序而不是控制器操作启动的后台任务。附近没有 HTTP 请求。 DI 在这里能为我做什么?有没有不回退到反模式的解决方案?我相信 ASP.NET Core DI 的创建者已经想到了这一点。

有没有办法让服务在那里解决,或者改变我的架构,以便后台任务本身以某种方式从 DI 中出来?

更新: 应评论请求,示例:控制器操作启动某事。这将需要很长时间,例如网络扫描。视图返回类似“亲爱的用户,请稍候,您可以观看此进度条”之类的内容。工作在后台继续,不断将进度和/或结果发布到浏览器。 (浏览器也可能轮询进度。)后台任务需要访问数据库来存储扫描结果。扫描完成后,浏览器可以通过另一个操作来获取它。因此,如果后台任务只使用控制器操作的 DbContext,那么随着操作完成,它将变得不可用。

另一个例子是与请求完全无关的后台服务。定期检查数据库然后执行某些操作的服务。那也需要一个 DbContext 并且没有地方可以尝试窃取它。

【问题讨论】:

  • 请添加您所面临问题的具体示例。
  • @Steven 我添加了一些示例。
  • 对不起,我应该让自己更清楚;我的意思是代码示例。你能展示一下相关代码吗?
  • 我没有准备好显示的代码。而且我不确定您需要查看哪些代码,我认为描述非常适合。想象一个控制器动作和一个使用 DbContext 的任务。就是这样。

标签: asp.net-core dependency-injection asp.net-core-2.1


【解决方案1】:

在这种情况下,您只能依赖作为反模式的 servicelocater-pattern。此外,DbContext 必须是每个依赖的实例(瞬态)而不是作用域。

我的建议是注入IServiceScopeFactory,它是一个单例,并在你的后台工作人员中开始一个作用域。

using (var scope = _serviceScopeFactory.CreateScope())
{
   var context = scope.ServiceProvider.GetRequiredService<DbContext>();
   // now do your work
}

没有别的了。这些东西不是 mvc 管道的一部分,因此它们无法即时解决。我还建议不要在某处直接访问 dbcontext。将东西包装在存储库中,然后使用该存储库,甚至将该存储库包装在所谓的服务类中。所以你的逻辑被封装了,你的后台工作者只是在收到消息时执行。

没有直接关系,但 ASP.NET-Core 内置了带有 IHostedService 的后台工作人员。

编辑:正如 Steven 在下面建议的那样,在手动解析/启动类时,它可能并不总是一种反模式。至少在 compositionroot 处理它时不会。这是他提供的link,那里解释得很好。

【讨论】:

  • 我讨厌它是迂腐的,但是对 ServiceProvider.GetService 的调用是否是服务定位器反模式的实现,取决于它来自 什么位置用过的。如果从Composition Root 内部调用,它不是 服务定位器。但是当组合根之外使用时,它是一个服务定位器。有关详细信息,请参阅this
  • 嘿史蒂文。感谢您的反馈意见。我会阅读并相应地更新答案。
  • 您缺少上下文对象的 .Dispose() 。这会泄漏。或者更好地使用 (var context = ...) { // 做你的工作 }
  • 不,它不会,因为在范围内解析的所有内容都会自动与范围一起处理。
猜你喜欢
  • 1970-01-01
  • 2020-09-26
  • 2019-07-15
  • 2021-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-23
  • 1970-01-01
相关资源
最近更新 更多