Why I should use AddScoped() for my repositories or services? Why not AddSingleton()?
I know about differences between them, but dont understand why I shouldn't use singleton instances to avoid creating new objects for each requests.
Can you explain it (preferably with examples :) )?
As you said, you know the difference so I won't get into that.
The reason you don't want addSingleton for your repositories or services is because typically your repositories and services are considered "business logic" and "persistence logic". And in your business logic you might have some class level variables that are getting set. Those properties would not be different for every request, they would be shared across the requests. (think of them like static properties).
Example:
Imagine you have a user service that sets the username of the user making the request as a class level variable.
Singleton logic:
Now imagine Bob makes a request to the api. The username would be set to "Bob" . Now imagine at the same time, John makes a request to the api. The username would get set to "John". But because the user service is a singleton, both John and Bob are sharing the same instance, meaning Bob's username would also be set to "John".
Scoped logic:
Imagine the exact same scenario as above, but this time when John makes a request, it does not override bobs username, because they are different instances.
The below three methods define the lifetime of the services,
AddTransient
Transient lifetime services are created each time they are requested. This lifetime works best for lightweight, stateless services.
AddScoped
Scoped lifetime services are created once per request.
AddSingleton
Singleton lifetime services are created the first time they are requested (or when ConfigureServices is run if you specify an instance there) and then every subsequent request will use the same instance.
Reference here
Imagine you have a aspnet-core project.
If you want to create an object only once during the program's runtime and use the same object each time, you should use addingingleton.
If you want an object to be new() again every time it receives a request while the program is running, you should use addscoped().
If you want an object to new() every request and response, you must use AddTransient.
Example value of 3 methods
Understanding with an infographic
Related
I've got a .Net Core project that needs to connect to around 4 different API services, I'm no expert with any of the HttpClient code, but from what I found, was that you'd generally only want to reuse one instance of your HttpClient. From what I can tell the general consensus is to use the HttpClientFactory in .Net Core by registering it in your Startup class and then requesting it using DI.
Now most of my default headers and such are all generally the same besides the BaseAddress url, how should I go about this when connecting to 4 diff API services? Should I register 4 different named clients or have one client with all the default information pre-set and then manually configure it as needed e.g. configuring the address?
General questions would be as I'm fairly new to this is, it's been said to re-use one instance of an HttpClient.
If I create 4 different named clients for each API service, wouldn't this create 4 instances of the HttpClient when I call the .CreateClient() method?
The .CreateClient() creates a new instance every time it's called, doesn't this defeat the purpose of having one instance of the HttpClient if say I need to make 3 different calls to one API service, each of those calls will call a .CreateClient() to establish some sort of connection and that will create 3 instances of the HttpClient?
Any help for clarity would be appreciated,
Thanks!
The purpose of using IHttpClientFactory is not to reuse instances of HttpClient. Instead, it is to reuse (by pooling) instances of HttpMessageHandler (actually HttpClientHandler, which is derived from the abstract HttpMessageHandler) that is the underlying object that manages HTTP connections & sockets. This diagram from Microsoft Docs shows it well.
You were worried that frequent calls to IHttpClientFactory.CreateClient() will create the same problem as frequent calls to new HttpClient(). However, this is not the case. As explained by Microsoft docs, the reason that frequent calls to new HttpClient() will result in socket exhaustion is that this constructor will create a new instance of HttpMessageHandler:
However, the issue isn't really with HttpClient per se, but with the default constructor for HttpClient, because it creates a new concrete instance of HttpMessageHandler, which is the one that has sockets exhaustion and DNS changes issues mentioned above.
You can see from the source code of IHttpClientFactory that it does not use the parameterless constructor of HttpClient in CreateClient(). Instead, it gets the HttpMessageHandler from a pool and inject it into the created HttpClient.
Whether you are using typed or named clients, you should use the HttpClient instance as if it's a transient object: it is cheap to create and you don't need to cache it for long periods of time.
Scenario
I am working to follow the IoC pattern and use the Microsoft DI Framework, but I'm hitting a wall and can't decide if it's my mindset, my approach, or I'm just doing it wrong.
I have a multi-tenant application that utilizes a Utility class to handle isolation and accessing the data of the tenant based on their unique configuration. The tenant is identified during authentication, but the tenant data has to be accessible and handled based on the request. This Utility class is registered under ConfigureServices in the Startup.cs and the constructor requires two parameters - a TenantDbContext and a Tenant.
public class TenantUtility{
public TenantUtility(TenantDbContext context, Tenant tenant){/*...*/}
}
Problem
Realizing that I'm probably pushing the limits of the DI Framework, I'm trying to build an implementationFactory in the Startup.cs. I've tried two approaches for accessing the tenant Id to build the Tenant object: one is using a User Claim, the second is a Route parameter.
services.AddTransient<TenantUtility>((svc)=> {
var tenantContext = svc.GetService<TenantDbContext>();
var accessor = svc.GetService<IHttpContextAccessor>();
var httpContext = accessor.HttpContext;
//httpContext is NULL...
//How do I get access to the tenant?
Common.Tenant t = new Common.Tenant();
//Set Tenant Identifier in t (once I get it)
return new StudentDataManager(tenantContext, t);
});
In both situations, when I setup the ImplementationFactory inside the Startup.cs, I don't have access to the user and I don't have access to the RouteData (or can't figure out how to get it) -- I even tried using IHttpContextAccessor, but the HttpContext property is null.
Am I approaching the pattern incorrectly? Should I be able to use DI for this level of detail be injected into the Utility before the Utility class is passed into the Controller?
You shouldn't pass in non-DI-managed types into services you want the container to provide for you (in this case, your Tenant parameter). Only request services that the container can provide. If you need a tenant, perhaps another service like an ITenantAccessor could be injected and would be able to get one.
I suspect your implementation could be done in middleware (if not using MVC) or as a filter (if using MVC). In either case, you can use DI from the filter or middleware class to inject your tenant service. In the class's invoke method, you will have access to the current context and request and should be able to do the things you need to. Remember that ConfigureServices runs before the app has started, so there is no context and no request is yet being made.
If you want to see some examples of filters, and especially how to do DI into filters, check out:
https://github.com/ardalis/GettingStartedWithFilters
and
http://ardalis.com/real-world-aspnet-core-mvc-filters
If you want to do it in middleware, then these might help:
https://github.com/ardalis/NotFoundMiddlewareSample
and
http://ardalis.com/using-custom-middleware-to-record-and-fix-404s-in-aspnet-core-apps
It seems to me that what you are injecting in the TenantUtility as a frist parameter is a valid abstraction (though it's probably better to use some interface), but the other one is a value-object. You don't generally inject value objects as they are not abstraction of some operations that you need to perform, but data. So I would pass the Tenant as a parameter to an operation on the TenantUtility class.
Another thing that I can suggest is to use a full-blown DI container like SimpleInjector (there are many others like Ninject, CastlWindsor, etc.). They are much more advanced as far as I know and can easily be integrated. Many of them have .Net Core integration already.
I'ld like to perform integration on stateless service in service fabric.Please help me on this. I have created the stateless service like c# web api.
In order to perform integration tests on your Reliable Service there is a number of dependencies you need to mock and take care of. You will not be able to test all situations or behavior of your service this way, the way the FabricRuntime hosts and runs services is difficult to replicate (without writing your own FabricRuntime equivalency). It is also worth noting that there is no way to run FabricRuntime without a cluster (including local development cluster).
You also need to consider how advanced your integration tests should be. For instance, does your service call out to other service (including actors) within the same cluster using fabric transport (the default communication model) that you want to include in your integration test? Do you need to ensure that state is persisted across multiple activations of the same service partition?
First you need to get rid of all hard dependencies to FabricRuntime (to things with dependencies to it) and also static support classes in your code:
Service/Actor proxy
Don't use the static ServiceProxy.Create<..)(..)> when calling other services, instead make sure your Service accepts an instance of IServiceProxyFactory in the constructor and use that instance to create proxies to services your service calls. Same goes for ActorProxy.Create<..>(..), replace this with an instance of IActorProxyFactory. In your program.cs where the service is constructed, give the service new ServiceProxyFactory() and new ActorProxyFactory(). That's the easy part, now you need to mock those so that your integration tests can actually create some form of proxy for downstream services. You will also need to create some form of container (like a mock FabricRuntime) that holds instances of called services and actors. It also gets tricky if you wan't to test that the RunAsync method of your service performs some function. Beware of creating this static though if you want to run it in a test runner,
you don't want different tests to get mixed up in the same container.
Service context
You need to mock your StatefulServiceContext well and how your Service is created. Your Service constructors need to accept an instance of StatefulServiceContext to pass along to the base class, so you are free to supply your own mocked instances of context there when you create the service.
public StatefulService(StatefulServiceContext serviceContext)
: base(serviceContext) {}
Service settings and activation context
You also need to see if your service implementation tries to read ICodePackageActivationContext or any of the settings from the Service manifest (like shown in this SO answer Where do you set and access run-time configuration parameters per environment for service fabric?). In that case you need to replace it with your own mockable version and you need to inject that in the constructor as well. What you find in most samples is a call to the service context, like this:
this.Context.CodePackageActivationContext.GetConfigurationPackageObject("Config");
If you do it this way in your service then you need make sure you have a mock of StatefulServiceContext as well and how your Service is created. When you register your service with the runtime in Program.Main() then you get and instance of StatefulServiceContext in the register call:
ServiceRuntime.RegisterServiceAsync("ServiceType",
context => new Service(context)).GetAwaiter().GetResult();
State
In order to mock state and get it to behave similar to what it will when running in a real cluster you need to mock the underlying handler for reliable state: IReliableStateManagerReplica and you need to add an overloaded constructor to your services that accepts an instance of that and sends it to the base:
public StatefulService(StatefulServiceContext serviceContext, IReliableStateManagerReplica reliableStateManagerReplica)
: base(serviceContext, reliableStateManagerReplica) {}
For actors its IActorStateProvider you need to mock if you want to handle state in your integration tests.
Summary
Depending on how advanced you want your integration tests to be and how close to the real execution model you want it to be, you may end up having to mock and replace a large number of classes/interfaces. The Web reference application sample
https://github.com/Azure-Samples/service-fabric-dotnet-web-reference-app has some implementation of Mocks for required classes, also https://github.com/loekd/ServiceFabric.Mocks contains Mocks for testing, although you might need to alter the code if you really want to run integration tests and not just unit tests.
There is no difference on your integration tests on stateless web api with a regular api.
I have a translation service and I need to expose a property that I want to use across my application.
services.AddScoped<IMyTranslator, MyTranslator>();
I use services.AddScoped to register this interface and its implementation. When I set a breakpoint to the constructor of MyTranslator, I can see that this class is initialized all the time.
I could not use AddSingleton, because it's shared across all sessions. I can not change the language for one user base on another user has changed language once.
I need a method that will initialize my middleware once per session.
The services.AddScoped is already scoped to the user request, each time a user request reaches the server, an instance is created to serve this specific request only and it is not shard with other users.
I have an application in ASP.NET MVC that also have a WCF Service included in the same proyect.
Im using Autofac to manage dependency injection. The problem is that when the application is accessed throught web, I need the dependencies to be instanced per Http request. And when the application is accessed throught WCF, I need the dependencies to be instanced per dependency.
In Castle.Windsor, there is a proyect to manage hybrid lifestyles (in this link).
I need something similar, something like:
builder.Register<UnitOfMeasureService>(x => new UnitOfMeasureService())
.As<IUnitOfMeasureService>().HybridLifetimeInstance();
Are there a workaround to manage the instance lifetime depending on when the application has a HttpContext or not?
Autofac does not have support for custom lifestyle managers.
Autofac lifetimes revolve around scopes, which are nestable and can be optionally tagged with a known ID. That's how instance-per-HTTP-request works: A nested scope "tagged" with a known value ("AutofacWebRequest") is created when a web request comes in. The hierarchy looks like this:
Container (root lifetime scope)
Web Reqeust Scope (tagged "AutofacWebRequest")
Any child scopes you might create in your code
When using InstancePerHttpRequest it's basically the same as InstancePerMatchingLifetimeScope("AutofacWebRequest"). If you resolve the type, it falls back until it finds a scope with that name and then uses the same instance in that tagged scope.
In standard WCF hosting, Autofac resolves everything out of a child scope you can get from the instance context (AutofacInstanceContext.Current.OperationLifetime). You could create a child lifetime scope from that and manually tag it, then resolve your dependencies like this:
var opScope = AutofacInstanceContext.Current.OperationLifetime;
using(var requestScope = opScope.BeginLifetimeScope("AutofacWebRequest"))
{
// Resolve InstancePerHttpRequest items from requestScope
}
However, there's no way to do that automatically and the WCF hosting mechanism isn't currently architected in a way you can "plug in" and do this - if you needed the web request scope automatically created, you'd have to roll your own WCF hosting mechanism based on the Autofac source code.
The other option is to have two different containers - one for your web stuff and one for your WCF stuff - and register the component with a different lifetime in each container.
Beyond that... there's really no way to "switch" lifetimes based on context. A component gets one lifetime declared and has to live with it for that component registry.