【问题标题】:Why is services.AddDbContext<dbContext>() makes dbContext as a Scoped service?Shoudln't be a Singleton service?为什么 services.AddDbContext<dbContext>() 使 dbContext 成为 Scoped 服务?不应该是 Singleton 服务吗?
【发布时间】:2019-04-17 07:25:16
【问题描述】:

我正在使用带有 Pomelo.EntityFramework.MySql 的 ASP.NET Core 2.2。

这是我的代码:

 services.AddDbContext<dbContext>(options => options.UseMySQL(appConfigsSection["DbConnectionString"]));
 services.AddSingleton<IUserService, UserService>();


 services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x=> {
                x.Events = new JwtBearerEvents
                {
                    OnTokenValidated = context =>
                    {
                        var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();       
                    }
                };

这是错误:

asp.net core 不能使用单例的作用域服务

就行了:

 var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>(); 

我的理解是DBContext应该作为Singleton服务使用,IUserService也是。 但似乎 DBContext 被视为 Scoped Service。

我可以通过将 IUserService 切换回 Scoped Service 轻松修复它。但我想知道为什么我不能将 DBContext 用作单一服务?

我认为 DBContext 应该用作 Singleton 服务,对吗?

here

【问题讨论】:

  • 是什么让你认为DbContext 应该是单身?
  • 绝对。即使范围可能太大了。 DbContext 就像一个 NHibernate 会话 - 瞬态、单用户并且本质上是断开连接的,它不应该在必要时保持活动状态。就像连接一样,由于连接池,创建或关闭并不昂贵。就像连接一样,如果它存在的时间过长,它就会积累变化。如果它的连接保持打开的时间过长,它会积累锁,导致数据库阻塞并可能出现死锁。
  • 鉴于 DbContext 的断开特性,caches 也会发生变化,就像 DataTable 一样,这意味着它不能被不同的线程/用户使用。所有这些都不是限制,因为它们使 DbContext fastscalable
  • 一个有意义的问题是why scoped instead of transient?在 Web 请求期间,如果代码多次请求相同的上下文,则将所有对象和更改缓存到请求结束,然后通过在最后一次调用 SaveChanges 将它们保存一次是有意义的。这将比在同一个请求期间执行例如 4 个方法更好,创建一个新的 CustomersContext 上下文来检索和修改 same 客户,然后保存更改 4 次,可能会覆盖彼此的更改

标签: c# entity-framework asp.net-core entity-framework-core


【解决方案1】:

DbContext 不应该用作单例,因为它持有一个不能被多个线程同时使用的连接对象。 如果两个请求同时尝试使用它,您将遇到错误。 如果您的服务依赖于上下文,则该服务不能是单例。

Scoped 很有意义,因为它允许您在服务之间传递 DB 对象并在所有服务中获取相同的 DbContext,这样您就可以在一个服务中查询实体并将更改保存在另一个服务中。

例如,如果您需要在两个服务中并行运行查询,您可以将其更改为瞬态。服务生命周期是 AddDbContext() 上的一个参数。

【讨论】:

  • 您能说得更具体些吗?您希望在哪里创建竞态条件以及使用什么设置?
  • 这不是 DbContexts 应该短命的唯一原因 - 只需考虑更改跟踪、关系修复和并发问题。
  • 主要问题不是线程安全。即使它是线程安全的,永久连接也会导致数据库中永久持有锁。 DbContext 意味着在调用SaveChanges 之前断开连接,因此会缓存更改。如果两个或更多线程/请求访问相同上下文,它们最终会影响彼此的对象和更改。
  • DataTable 的生命周期几乎相同。更改跟踪,断开连接,不打算长期存在
猜你喜欢
  • 1970-01-01
  • 2019-08-02
  • 1970-01-01
  • 2021-10-20
  • 2022-07-29
  • 2020-04-23
  • 1970-01-01
  • 2021-07-07
  • 1970-01-01
相关资源
最近更新 更多