使用IServiceCollection.AddTransient,IServiceCollection.AddSingleton和IServiceCollectionAddScopped方法的实际场景是什么?

时间:2017-03-05 13:28:54

标签: c# asp.net-core

在阅读this帖后,我可以理解AddTransientAddScoppedAddSingleton之间的差异,但是,我无法看到每个内容的实际用法。

我的理解是

AddTransient

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

services.AddTransient<IDataAccess, DataAccess>();
每次客户端代码请求时,

都将返回一个新的DataAccess对象。更可能是构造函数。

AddTransient的使用

如果我们必须访问数据库来读取和更新它并销毁访问对象(DataAccess),最好使用AddTransient - 不确定线程​​安全性。

AddScopped

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

使用AddScopped

 services.AddScoped<ShoppingCart>(serviceProvider => ShoppingCart.GetShoppingCart(serviceProvider));

这意味着每个Web请求都将拥有自己的购物车实例,实习生意味着每个用户/客户将拥有自己的购物车实例,用于该http网络请求。

AddSingleton

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

使用AddSingleton

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

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); 

有人可以在使用AddSingleton时提供一个不错的实际示例,并检查我对AddTransient和AddScopped的理解是否正确?

2 个答案:

答案 0 :(得分:15)

您对所有3个范围的理解是正确的。

无法共享组件时将使用

瞬态。非线程安全的数据库访问对象就是一个例子。

Scoped 可用于Entity Framework数据库上下文。主要原因是从数据库获取的实体将附加到请求中的所有组件看到的相同上下文。当然,如果您计划并行查询,则无法使用Scoped。

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

总是共享

Singleton 组件,因此它们最适合不需要绑定到请求的线程安全组件。一个示例是IOptions,它可以访问配置设置。在单个静态HttpClient实例上使用SendAsync的{​​{1}}包装器类也将完全是线程安全的,并且是成为Singleton的良好候选者。

请注意,如果您有一个依赖于Scoped组件的Singleton组件,它的依赖关系将在它之前被释放。因此,组件不能依赖于范围小于其自身的另一个组件。

答案 1 :(得分:1)

我已经看到了“只使用AddTransient<T>()”视图,但我不同意。

考虑内存分配

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

AddSingleton()

这是ApplicationInsights TelemetryClient实例作为单例。他们的文档说这行得通。

telemetryClient = new TelemetryClient(TelemetryConfiguration.Active);
services.AddSingleton<TelemetryClient>(telemetryClient);

在该项目中,我也使用Azure表存储,并且我发现将CloudTableClient创建为单例也很好。我不需要为每个请求都继续创建它的实例。

CloudStorageAccount storageAccount = CloudStorageAccount.Parse(Configuration.GetValue<string>("storageAccountConnectionString"));
CloudTableClient someTableClient = storageAccount.CreateCloudTableClient();
services.AddSingleton<CloudTableClient>(someTableClient);

从某种意义上讲,它等效于类的readonly静态属性,例如:

public static readonly CloudTableClient cloudTableClient = new CloudTableClient(...);

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

AddScoped()

对我来说,AddScoped<T>()的一个示例是我想将获取应用程序见解所需的JavaScript嵌入到网页中,但是我使用了Content-Security-Policy,因此需要在其上添加一个随机数。任何页面JavaScript。我有一些代码可以帮助我做到这一点。

services.AddScoped<ApplicationInsightsJsHelper>();

AddTransient()

我还没有发现需要使用AddTransient<T>()。可能是因为我没有想到每次需要它们作为“服务”时都会创建的东西……它们只是我新创建的变量。从某种意义上讲,AddTransient<T>()是对Factory模式的隐藏使用……您可以使用依赖注入(有效地)为您做同样的事情,而不是调用静态的MyServiceFactory.Create()函数。