从后台任务访问 DbContext 服务 [英] Access DbContext service from background task

查看:42
本文介绍了从后台任务访问 DbContext 服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

So ASP.NET Core applications have Dependency Injection built right in. And with Entity Framework Core, you can easily get a scoped DbContext instance from a controller action method.

但这仅限于控制器操作.如果您需要从一个动作开始一个长时间运行的后台任务,该动作将通过其他方式(如 WebSocket)与浏览器中的视图进行通信,那么您会突然一无所有.后台任务不能使用操作的 DbContext,因为它在操作返回时被限定和处理.

But this is all limited to controller actions. If you need to start a long-running background task from an action that will communicate with the view in the browser by other means like WebSocket, then you suddenly have nothing at all. The background task can't use the action's DbContext because that was scoped and disposed of when the action returns.

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

An easy way would be to use what people call a Service Locator. This is a static copy of some IServiceProvider for later access and service resolution. (ASP.NET Core 2.1 might need a different approach as I've read in this comment.) But whereever I look, this is described as anti-pattern. It makes testing harder and obfuscates dependencies. Alright.

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

So what's the recommended solution for this scenario? I'm somewhere in the middle of nowhere. A background task that might even be started from a scheduler instead of a controller action. No HTTP request anywhere near. What can DI do for me here? Is there a solution without falling back to anti-patterns? I'm sure the creators of ASP.NET Core DI have thought of this.

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

Is there either a way to get the services resolved there, or change my architecture so that the background task itself comes out of DI somehow?

更新: 由评论请求,示例:控制器操作启动某事.这将需要很长时间,就像网络扫描一样.视图返回类似亲爱的用户,请稍候,您可以观看此进度条".工作在后台继续,不断将进度和/或结果发布到浏览器.(浏览器也可能会轮询进度.)后台任务需要访问数据库以存储扫描结果.扫描完成后,浏览器可以通过另一个操作获取它.因此,如果后台任务仅使用控制器操作的 DbContext,则在操作完成后将无法使用.

Update: Requested by a comment, an example: A controller action starts something. This will take a long time, like a network scan. The view returns with something like "Dear user, please wait while you can watch this progress bar." Work continues in the background, continually posting the progress and/or results to the browser. (The browser might also poll progress instead.) The background task needs access to the database to store the scan results. When the scan is finished, the browser can fetch it through another action. So if the background task would just use the controller action's DbContext, that would become unusable as the action has completed.

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

Another example is a background service that isn't related to a request at all. A service that regularly checks the database and then does something. That also needs a DbContext and has nowhere to even try to steal it.

推荐答案

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

In that case you can only rely on the servicelocater-pattern which is an anti-pattern. Also the DbContext must be instance-per-dependency (transient) rather than scoped.

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

My suggestion is to inject IServiceScopeFactory which is a singleton and the beginn a scope in your background-worker that does the deed.

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

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

There is no other. These things are not part of the mvc pipeline so they cannot be resolved on the fly. I would also suggest not to directly access the dbcontext somewhere. Wrap things in a repository and then use that repository or even wrap that repository in a so called service class. So your logic is encapsulated and your background-worker just executes things when receiving a message.

不直接相关,但 ASP.NET-Core 内置了带有 IHostedService.

Not directly related, but ASP.NET-Core has background-worker built-in with IHostedService.

正如史蒂文在下面建议的那样,手动解析/启动类时它可能并不总是反模式.至少在组合根处理它时不会.这是他提供的链接,其中解释得很好.

As Steven suggested below, it might not always be an anti-pattern when manually resolving / initiating classes. At least not when the compositionroot is taking care of it. Here is a link he provided, where it is explained quite good.

这篇关于从后台任务访问 DbContext 服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆