为什么要使用AddScoped()而不是AddSingleton()?

3
为什么我应该在我的存储库或服务中使用AddScoped(),而不是AddSingleton()呢?为什么不能使用单例实例来避免为每个请求创建新对象? 我知道它们之间的差异,但不明白为什么我不应该使用单例模式(singleton)。 你能解释一下吗?最好给出一些示例 :)

AddSingleton() 是单例模式,它在整个容器中是唯一的,因此当程序运行时,它的实例是唯一的。AddScoped() 在特定领域中是唯一的,而这些领域之间互不影响。 - Qing Guo
如果您正在使用Entity Framework作为ORM,则无法将DbContext注册为Singleton,因为它不是线程安全的。因此,您必须通过AddDbContext将其注册为瞬态。 - Peter Csala
这一切都关乎于存储请求特定状态。有两种模型可用于存储请求特定状态。在一个模型中,您可以在图形中的对象变量中捕获运行时数据。这需要使用Scoped生命周期。但是还有另一个模型,它将运行时数据保留在已解析的对象之外,并将其存储为环境数据。这允许对象被注册为单例,因为它们本身没有任何状态。 - Steven
2个回答

8

您所说,您知道差异,因此我不会深入讨论。

您不希望为存储库或服务添加addSingleton的原因是,通常您的存储库和服务被认为是“业务逻辑”和“持久性逻辑”。 在您的业务逻辑中,可能会有一些类级变量正在设置。这些属性对于每个请求都不会有所不同,它们会在请求之间共享 (就像静态属性一样)。

例如:

想象一下您有一个用户服务,该服务将发出请求的用户的用户名设置为类级变量。

Singleton逻辑:

现在想象一下Bob向API发送请求。 用户名将设置为“Bob”。 现在想象一下,在同一时间,John向API发送请求。 用户名将设置为“John”。 但由于用户服务是单例,因此John和Bob共享相同的实例,这意味着Bob的用户名也将设置为“John”。

Scoped逻辑:

想象与上述完全相同的情况,但是这次当John发出请求时,它不会覆盖Bob的用户名,因为它们是不同的实例。


1
以下三种方法定义了服务的生命周期:
  1. AddTransient 每次请求时都会创建瞬态生命周期服务。这种生命周期最适合轻量级、无状态的服务。

  2. AddScoped 每个请求只会创建一次作用域生命周期服务。

  3. AddSingleton 单例生命周期服务在第一次请求时创建(或者在 ConfigureServices 中指定实例时运行),然后每个后续请求都将使用同一个实例。

参考文献

假设您有一个 aspnet-core 项目。
  • 如果您想在程序运行期间仅创建一个对象并每次使用相同的对象,则应使用 AddSingleton。

  • 如果您希望在程序运行时每次接收到请求时都创建一个新的对象,则应使用 AddScoped()。

  • 如果您希望在每个请求和响应中都创建一个新的对象,则必须使用 AddTransient。

Example value of 3 methods

通过信息图形了解编程


在典型情况下,Scoped 的定义是正确的 :) 从技术上讲,Scoped 服务不是每个请求创建一次,而是每个服务范围创建一次。只是恰好 ASP.NET Core 为每个请求创建一个作用域。但是您也可以在应用程序中创建自己的作用域,即使在同一请求期间,它们也会获得不同的实例。 - juunas
@juunas,你能编辑我的回答吗? - KOMODO

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接