Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the practical scenarios to use IServiceCollection.AddTransient, IServiceCollection.AddSingleton and IServiceCollectionAddScoped Methods?

Tags:

After reading this post I can understand the differences between AddTransient,AddScoped and AddSingleton however, I am unable to see the practical usage of each of them.

My understanding is

AddTransient

Creates a new instance every time when the client asks for it.

services.AddTransient<IDataAccess, DataAccess>(); 

will return a new DataAccess object every time a client code asks for it. More likely a constructor.

Usage of AddTransient

In cases when we have to access a database to read and update it and destroy the access object (DataAccess) its best to use AddTransient - Not sure about the thread safty.

AddScoped

Creates a new instance for each http web request.

Usage of AddScoped

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

this mean each web request will be having its own shopping cart instance which intern means each user / client will be having its own shoping cart instance for that http web request.

AddSingleton

Create single instance for all the http web requests.

Usage of AddSingleton

Found this code in an sample application but I dont understand how it is being useful.

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();  

Can someone please give a decent practical example when to use AddSingleton and check if my understanding of AddTransient and AddScoped is correct?

like image 550
Yawar Murtaza Avatar asked Mar 05 '17 13:03

Yawar Murtaza


People also ask

When should I use AddSingleton?

AddSingleton: Is used for instances that can be shared across the application. It is ideal for caching or to be used for objects that are costly to instantiate. Be careful not to accidentally make singletons of services that has state which should not be shared, especially if it is sensitive user data.

When should I use AddTransient?

This is a lifetime service and that was created each and every time they are requested. it provides the best lightweight, stateless services. AddTransient would be used when the component cannot be shared. A non-thread-safe database use object would be one example.

What is difference between AddTransient and AddScoped and AddSingleton?

Singleton is a single instance for the lifetime of the application domain. Scoped is a single instance for the duration of the scoped request, which means per HTTP request in ASP.NET. Transient is a single instance per code request.

When should I use IServiceProvider?

The IServiceProvider is responsible for resolving instances of types at runtime, as required by the application. These instances can be injected into other services resolved from the same dependency injection container. The ServiceProvider ensures that resolved services live for the expected lifetime.


2 Answers

Your understanding of all 3 scopes is correct.

Transient would be used when the component cannot be shared. A non-thread-safe database access object would be one example.

Scoped can be used for Entity Framework database contexts. The main reason is that then entities gotten from the database will be attached to the same context that all components in the request see. Of course if you plan on doing queries with it in parallel, you can't use Scoped.

Another example of a Scoped object would be some kind of a RequestContext class, that contains e.g. the username of the caller. A middleware/MVC filter can request it and fill out the info, and other components down the line can also request for it, and it will surely contain the info for the current request.

Singleton components are shared always, so they are best for thread-safe components that do not need to be bound to a request. An example would be IOptions, which gives access to configuration settings. An HttpClient wrapper class that uses SendAsync on a single static HttpClient instance would also be completely thread-safe, and a good candidate for being a Singleton.

Note that if you have a Singleton component that depends on a Scoped component, its dependency would get disposed before it. Thus a component cannot depend on another component that has smaller scope than itself.

like image 153
juunas Avatar answered Oct 29 '22 04:10

juunas


I've seen the "just use AddTransient<T>()" view, but I don't agree.

Think about memory allocation

I hate allocating things when I don't have to, so if I know I'm creating something that's thread-safe, or that I have explicit documentation that having a singleton instance is the expected usage, then I'm creating a singleton.

AddSingleton()

Here's the ApplicationInsights TelemetryClient instance as a singleton. Their documentation says this works.

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

In this project I use Azure Table Storage as well, and I've found that creating a CloudTableClient as a singleton works just fine. I don't need to keep creating instances of it for every request.

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

In some sense, it's the equivalent of a class's readonly static property, for instance:

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

... there's only one instance of it in the whole application, but by using services.AddSingleton<T>() we get direct access to it using Dependency Injection.

AddScoped()

An example of AddScoped<T>() for me is that I want to embed the JavaScript that I need to get Application Insights into a web page, but I use Content-Security-Policy, so I need to put a nonce on any on-page JavaScript. I have a little bit of code that helps me do it.

services.AddScoped<ApplicationInsightsJsHelper>(); 

AddTransient()

I haven't found a need to use AddTransient<T>() for anything yet. It could be that I don't think of things that I have to create, every time I need them, as "services"... they're just variables that I new up. In some sense, AddTransient<T>() is a hidden use of the Factory pattern... instead of calling a static MyServiceFactory.Create() function, you have Dependency Injection (effectively) do the same thing for you.

like image 26
Scott Avatar answered Oct 29 '22 04:10

Scott