首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用IServiceCollection.AddTransient、IServiceCollection.AddSingleton和IServiceCollectionAddScoped方法的实际场景是什么?

使用IServiceCollection.AddTransient、IServiceCollection.AddSingleton和IServiceCollectionAddScoped方法的实际场景是什么?
EN

Stack Overflow用户
提问于 2017-03-05 21:28:54
回答 2查看 9.8K关注 0票数 22

在阅读了this的帖子后,我可以理解AddTransientAddScopedAddSingleton之间的区别,但是我看不到它们各自的实际用法。

我的理解是

AddTransient

每次客户端请求时,都会创建一个新实例。

代码语言:javascript
复制
services.AddTransient<IDataAccess, DataAccess>();

每次客户端代码请求它时,都将返回一个新的DataAccess对象。更像是一个构造函数。

AddTransient的用法

在我们不得不访问数据库来读取和更新数据库并销毁访问对象(DataAccess)的情况下,最好使用AddTransient -不确定线程的安全性。

AddScoped

为每个http web请求创建一个新实例。

AddScoped用法

代码语言:javascript
复制
 services.AddScoped<ShoppingCart>(serviceProvider => ShoppingCart.GetShoppingCart(serviceProvider));

这意味着每个web请求将具有其自己购物车实例,这意味着每个用户/客户端将具有针对http web请求的其自己的购物车实例。

AddSingleton

为所有http web请求创建单个实例。

AddSingleton用法

我在一个示例应用程序中找到了这段代码,但我不明白它是如何有用的。

代码语言:javascript
复制
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); 

有没有人能给出一个合适的实际例子,看看我对AddSingleton和AddScoped的理解是否正确?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-03-06 15:12:05

您对所有3个作用域的理解都是正确的。

当组件无法共享时,将使用瞬态。非线程安全的数据库访问对象就是一个例子。

作用域可用于实体框架数据库上下文。主要原因是,从数据库中获取的实体将附加到请求中的所有组件都能看到的相同上下文。当然,如果您计划使用它并行执行查询,则不能使用作用域。

作用域对象的另一个例子是某种RequestContext类,它包含例如调用者的用户名。中间件/MVC过滤器可以请求它并填写信息,其他组件也可以请求它,它肯定会包含当前请求的信息。

单例组件总是共享的,因此它们最适合不需要绑定到请求的线程安全组件。IOptions就是一个例子,它允许访问配置设置。在单个静态HttpClient实例上使用SendAsyncHttpClient包装类也是完全线程安全的,并且是一个很好的单例候选者。

请注意,如果您有一个依赖于作用域组件的Singleton组件,那么它的依赖项将在它之前被释放。因此,一个组件不能依赖于另一个作用域小于其自身的组件。

票数 30
EN

Stack Overflow用户

发布于 2019-05-18 16:19:15

我看过“只使用AddTransient<T>()”的观点,但我不同意。

考虑内存分配

我讨厌在不必要的时候分配东西,所以如果我知道我正在创建线程安全的东西,或者我有明确的文档说明拥有一个单例实例是预期的用法,那么我就是在创建一个单例实例。

AddSingleton()

下面是作为单例的ApplicationInsights TelemetryClient实例。他们的文档说这是可行的。

代码语言:javascript
复制
telemetryClient = new TelemetryClient(TelemetryConfiguration.Active);
services.AddSingleton<TelemetryClient>(telemetryClient);

在这个项目中,我也使用了Azure Table Storage,我发现将CloudTableClient创建为单例效果很好。我不需要为每个请求都创建它的实例。

代码语言:javascript
复制
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(Configuration.GetValue<string>("storageAccountConnectionString"));
CloudTableClient someTableClient = storageAccount.CreateCloudTableClient();
services.AddSingleton<CloudTableClient>(someTableClient);

在某种意义上,它等同于类的只读静态属性,例如:

代码语言:javascript
复制
public static readonly CloudTableClient cloudTableClient = new CloudTableClient(...);

..。在整个应用程序中只有一个它的实例,但是通过使用services.AddSingleton<T>(),我们可以通过依赖注入直接访问它。

AddScoped()

对我来说,AddScoped<T>()的一个例子是,我想要将获取应用程序洞察所需的JavaScript嵌入到web页面中,但我使用的是Content-Security-Policy,因此我需要在页面上的任何JavaScript上放置一个现时值。我有一些代码可以帮助我做到这一点。

代码语言:javascript
复制
services.AddScoped<ApplicationInsightsJsHelper>();

AddTransient()

我还没有发现需要使用AddTransient<T>()做任何事情。这可能是我不认为我必须创建的东西,每次我需要它们时,作为“服务”……它们只是我新添加的变量。从某种意义上说,AddTransient<T>()是工厂模式的一种隐藏用途……您可以(有效地)让依赖项注入为您做同样的事情,而不是调用静态MyServiceFactory.Create()函数。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42608918

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档