在阅读了this的帖子后,我可以理解AddTransient
,AddScoped
和AddSingleton
之间的区别,但是我看不到它们各自的实际用法。
我的理解是
AddTransient
每次客户端请求时,都会创建一个新实例。
services.AddTransient<IDataAccess, DataAccess>();
每次客户端代码请求它时,都将返回一个新的DataAccess对象。更像是一个构造函数。
AddTransient的用法
在我们不得不访问数据库来读取和更新数据库并销毁访问对象(DataAccess)的情况下,最好使用AddTransient
-不确定线程的安全性。
AddScoped
为每个http web请求创建一个新实例。
AddScoped的用法
services.AddScoped<ShoppingCart>(serviceProvider => ShoppingCart.GetShoppingCart(serviceProvider));
这意味着每个web请求将具有其自己购物车实例,这意味着每个用户/客户端将具有针对http web请求的其自己的购物车实例。
AddSingleton
为所有http web请求创建单个实例。
AddSingleton的用法
我在一个示例应用程序中找到了这段代码,但我不明白它是如何有用的。
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
有没有人能给出一个合适的实际例子,看看我对AddSingleton和AddScoped的理解是否正确?
发布于 2017-03-06 15:12:05
您对所有3个作用域的理解都是正确的。
当组件无法共享时,将使用瞬态。非线程安全的数据库访问对象就是一个例子。
作用域可用于实体框架数据库上下文。主要原因是,从数据库中获取的实体将附加到请求中的所有组件都能看到的相同上下文。当然,如果您计划使用它并行执行查询,则不能使用作用域。
作用域对象的另一个例子是某种RequestContext
类,它包含例如调用者的用户名。中间件/MVC过滤器可以请求它并填写信息,其他组件也可以请求它,它肯定会包含当前请求的信息。
单例组件总是共享的,因此它们最适合不需要绑定到请求的线程安全组件。IOptions
就是一个例子,它允许访问配置设置。在单个静态HttpClient
实例上使用SendAsync
的HttpClient
包装类也是完全线程安全的,并且是一个很好的单例候选者。
请注意,如果您有一个依赖于作用域组件的Singleton组件,那么它的依赖项将在它之前被释放。因此,一个组件不能依赖于另一个作用域小于其自身的组件。
发布于 2019-05-18 16:19:15
我看过“只使用AddTransient<T>()
”的观点,但我不同意。
考虑内存分配
我讨厌在不必要的时候分配东西,所以如果我知道我正在创建线程安全的东西,或者我有明确的文档说明拥有一个单例实例是预期的用法,那么我就是在创建一个单例实例。
AddSingleton()
下面是作为单例的ApplicationInsights TelemetryClient实例。他们的文档说这是可行的。
telemetryClient = new TelemetryClient(TelemetryConfiguration.Active);
services.AddSingleton<TelemetryClient>(telemetryClient);
在这个项目中,我也使用了Azure Table Storage,我发现将CloudTableClient创建为单例效果很好。我不需要为每个请求都创建它的实例。
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(Configuration.GetValue<string>("storageAccountConnectionString"));
CloudTableClient someTableClient = storageAccount.CreateCloudTableClient();
services.AddSingleton<CloudTableClient>(someTableClient);
在某种意义上,它等同于类的只读静态属性,例如:
public static readonly CloudTableClient cloudTableClient = new CloudTableClient(...);
..。在整个应用程序中只有一个它的实例,但是通过使用services.AddSingleton<T>()
,我们可以通过依赖注入直接访问它。
AddScoped()
对我来说,AddScoped<T>()
的一个例子是,我想要将获取应用程序洞察所需的JavaScript嵌入到web页面中,但我使用的是Content-Security-Policy,因此我需要在页面上的任何JavaScript上放置一个现时值。我有一些代码可以帮助我做到这一点。
services.AddScoped<ApplicationInsightsJsHelper>();
AddTransient()
我还没有发现需要使用AddTransient<T>()
做任何事情。这可能是我不认为我必须创建的东西,每次我需要它们时,作为“服务”……它们只是我新添加的变量。从某种意义上说,AddTransient<T>()
是工厂模式的一种隐藏用途……您可以(有效地)让依赖项注入为您做同样的事情,而不是调用静态MyServiceFactory.Create()
函数。
https://stackoverflow.com/questions/42608918
复制相似问题