提问人:Subin Jacob 提问时间:11/16/2023 更新时间:11/16/2023 访问量:117
.net core 控制台应用程序中的 AddScoped 和 AddSingleton 之间有什么区别?
What's the difference between AddScoped and AddSingleton in .net core Console Application?
问:
在 ASP.NET 上下文中,一个的范围被理解,即在请求级别。当涉及到控制台应用程序时,它没有请求上下文,对吧?它将如何表现?AddScoped
services.AddScoped<SomeServiceClass>();
services.AddSingleton<SomeServiceClass>();
答:
5赞
Tim Maes
11/16/2023
#1
在控制台应用程序中,没有像 Web 上下文中那样的请求的内置概念。因此,如果在控制台应用程序中使用依赖关系注入 (DI),则必须手动管理服务范围。
using (var scope = serviceProvider.CreateScope())
{
var service = scope.ServiceProvider.GetRequiredService<SomeServiceClass>();
// use service here
}
不过,单例的行为是相同的
3赞
Guru Stron
11/16/2023
#2
在请求级别。当涉及到控制台应用程序时,它没有请求上下文,对吧?
是的,在 ASP.NET 中,核心框架将创建为每个请求的范围。在控制台应用程序中,没有开箱即用的“请求”概念,但可以在需要时手动创建范围(当您有一些迭代和/或长时间运行的处理时,例如涉及 EF Core 时,这可能很有用):DbContext
var services = new ServiceCollection();
// services.Add...
var serviceProvider = services.BuildServiceProvider();
while (some_condition)
{
using var scope = serviceProvider.CreateScope();
var service = scope.ServiceProvider.GetRequiredService<ISomeService>();
service.DoSomething();
}
主要区别在于,启用范围验证后,无法从根范围解析作用域服务(这样做是为了防止类似于强制依赖项“引入”的负面影响):
var services = new ServiceCollection();
// services.Add...
services.AddScoped<object>();
var serviceProvider = services.BuildServiceProvider(new ServiceProviderOptions
{
ValidateScopes = true, // can be detrimental for perf, disable on Prod
// ValidateOnBuild = true
});
// InvalidOperationException: Cannot resolve scoped service 'System.Object' from root provider:
var service = serviceProvider.GetRequiredService<object>();
范围
- 对于 Web 应用程序,作用域生存期指示每个客户端请求(连接)创建一次服务。向 AddScoped 注册作用域内的服务。
- 在处理请求的应用中,作用域内服务在请求结束时被释放。
- 使用 Entity Framework Core 时,默认情况下,AddDbContext 扩展方法会注册具有作用域生存期的 DbContext 类型。
单例 创建单例
生存期服务:
- 第一次请求它们。
- 由开发人员直接向容器提供实现实例时。
来自依赖关系注入容器的服务实现的每个后续请求都使用相同的实例。
单一实例服务必须是线程安全的,并且通常用于无状态服务。
在处理请求的应用中,当应用程序关闭时释放单一实例服务时,将释放单一实例服务。由于在应用关闭之前不会释放内存,因此请考虑将内存用于单一实例服务。
ServiceProvider
评论
0赞
Subin Jacob
11/17/2023
因此,如果我不显式创建新范围,它将如何表现?瞬态还是单例?
0赞
Guru Stron
11/17/2023
@SubinJacob这取决于设置。如果您启用了验证(我建议在非生产环境中使用),它将引发异常。否则,它将是每个作用域一个依赖项,因此是一个依赖项,因为您只有根作用域。
0赞
Subin Jacob
11/17/2023
这就是我从 ChatGPT 那里得到的“ 服务被注册为有范围的服务,但它们实际上的行为类似于瞬态服务。换言之,每次在不创建作用域的情况下请求作用域服务时,都会创建该服务的新实例”。但是当我尝试使用代码时,它的行为类似于单例作用域。
0赞
Guru Stron
11/17/2023
@SubinJacob“这是我从 ChatGPT 那里得到的”——你认为这是正确的,为什么?“它的行为就像一个单例示波器”——是的,正如我所写的。
0赞
Guru Stron
11/17/2023
@SubinJacob,如果你不创建作用域,你仍然有一个作用域 - 根作用域,并且每个作用域只能有一个作用域依赖项,如果你只使用根作用域,它基本上是一个单例。
1赞
Selaka Nanayakkara
11/16/2023
#3
尽管这与 Web 应用程序的依赖注入不同。概念保持不变。
AddScoped:
- 每个作用域创建一次服务。在 Web 应用程序的上下文中,这通常意味着每个 HTTP 请求一次。
- 在控制台应用程序性质中,作用域可能与特定操作相关。
AddSingleton:
- 服务仅创建一次,并在应用程序的生存期内重复使用
- 在控制台应用程序中,这意味着在创建服务时 首先被请求并在整个持续时间内重复使用 应用。
通过官方文档阅读有关依赖注入的更多信息 此处
评论