Dependency Injection lifetimes for a Factory - c#

I have a .Net Core 3.1 web API, and I have the followings dependencies:
As Scoped SomeDbContext (using AddDbContextPool).
As Transient SomeDbRepository, it recive the above SomeDbContext.
As Transient SomeService, it recive the above SomeDbRepository.
As Singleton a factory for SomeService.
Here the code for injecting the dependencies in Startup.cs
services.AddDbContextPool<SomeDbContext>(options => options.UseSqlServer("connectionsString"));
services.AddTransient<SomeDbRepository>();// recive SomeDbContext
services.AddTransient<SomeService>();// recive SomeDbRepository
//Factory for SomeService
services.AddSingleton<Func<SomeService>>(provider => () =>
{
return provider.GetService<SomeService>();
});
API Controller
//API Controller
public SomeController(Func<SomeService> factory)
{
_someService = factory.Invoke();
}
When I call my API in a multi thread enviroment I get the error:
Error: A second operation started on this context before a previous operation
completed. This is usually caused by different threads using the same
instance of DbContext
Why is my DbContext used by different threads? It suposse the Factory returns a new scoped DbContext per request. I use (Invoke) the Factory only one time por request.
If I change the lifetime of the Factory, from Sinlgeton to Scoped, it works ok. But I dont know Why? Why the lifetime of the Factory affects? Could someone explain me why it works that way. Thank a lot guys!!

The IServiceProvider parameter of the delegate of a Singleton registration provides a reference to the root scope. Scoped (and IDisposable Transient) services are tracked in the scope they are resolved from and since the root provider has its own scope, resolving from the root IServiceProvider causes Scoped (and IDisposable Transient) services to be cached for the lifetime of that root provider. This typically means: they live for as long as the application runs.
What this means is that, in the context of the MS.DI container, it is typically a bad idea to register delegates as Singleton that resolve from the IServiceProvider parameter, because it causes resolved Scoped depedendencies to accidentally become Singletons (they become accidental Captive Dependencies). With IDisposable Transients it becomes even more implicit, because resolving them from the root provider could even cause memory leaks, because they will only get released when the application shuts down.
Although it is fine to register a delegate as Singleton when it only resolves other Singletons (or non-disposable Transients), this is typically quite fragile, because it's easy to change this in the future, in a way that accidentally causes trouble.
Instead, with MS.DI, it's best to register your factory delegates as Scoped:
services.AddScoped<Func<SomeService>>(provider => () =>
{
return provider.GetService<SomeService>();
});
Note that this advise is specific to MS.DI and might not be appliable to other DI Containers.

Related

InvalidOperationException: Cannot consume scoped service 'Microsoft.JSInterop.IJSRuntime' from singleton '...IAuthentication' in Blazor

I'm creating Blazor project that at first everything works fine until I need to inject IJSRuntime into cs file.
Microsoft.JSInterop;
...
...
public BaseService(IJSRuntime jSRuntime)
{
}
BaseService is inherited in another service named AuthenticationServices which is also uses an Interface called IAuthentication. Thus
using Microsoft.JSInterop;
public class AuthenticationServices : BaseService, IAuthentication
{
public AuthenticationServices(IJSRuntime jSRuntime) : base(jSRuntime)
{
}
}
My issue is in Startup.csfile which has this code
services.AddSingleton<IAuthentication, AuthenticationServices>();
If I run the app it says,
InvalidOperationException: Cannot consume scoped service 'Microsoft.JSInterop.IJSRuntime' from singleton '...IAuthentication'
What does it mean? Am I doing it correctly that I only need something to add?
Dependency injection in the Blazor has 3 different lifetime policies.
Singleton
Scope
Transient
Singleton
This means that any service of that type will have only one instance.
Scope
This lifetime mean that for set of object created scope and within that scope will be just one instance. Usually in most scenarios, scope is created for processing User Session (Client-side Blazor) or User connection (Server-side Blazor). You can compare with scope per single HTTP request (ASP.NET).
Transient
Object with this lifetime created each time they are requested. It's same to regular new.
Lifetime consumption rules
Given the nature of these object lifetime policies, following rules for consuming services applies.
Transient service can consume Transient, ScopedandSingleton` services.
Scoped service can consume Scoped and Singleton services. But cannot consume Transient services.
Singleton services can consume only Singleton services. But cannot consume Transient and Scoped services.
Service IJSRuntime registered inside Blazor as Scoped service, as such it can be used only by Scoped and Transient services.
So you either have to make AuthenticationServices the Scoped service, or get rid of IJSRuntime as constructor parameter.

What lifetime scope to use when using an instance in a separate thread?

I have a WebApi project and in a controller I'm using HostingEnvironment.QueueBackgroundWorkItem to start a job in a separate thread:
public IHttpActionResult DoJob()
{
HostingEnvironment.QueueBackgroundWorkItem(ct =>
{
var service = new MyService(logService, userInfo);
var entity = service.DoJob(ct);
});
return Ok();
}
Currently, in the above I'm using a concrete instance (which I want to replace) of my service . I also use Autofac and for my services, I configured as follows:
builder.RegisterAssemblyTypes(assemblies)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces()
.InstancePerRequest();
The above registration works fine for all services when using normally within a request.
Will the above registration also work for services when run in a separate thread after the request terminates?
Will the above registration also work for services when run in a separate thread after the request terminates?
Yes the configuration for the registration will work.
Whatever method you call in your service may or may not work:
What this means is that if you try to resolve components that are registered as instance-per-request but there’s no current request… you’re going to get an exception..
Either one of two following cases are correct.
You might get autofac to work sometimes, because the request still exists, but sometimes won't because the request ends.
or (most likely)
the execution of QueueBackgroundWorkItem() is outside the lifetime scope so it won't work at all.
So ultimately your service should create it's own lifetime scope (IDisposable etc etc).
Dependency injection is nothing to do with thread, unless we missed to configure the dependency injection of all the accessible members of that thread at the start of the application/service.

.NET Core DI scope lifetime in Ninject

Edit: Due to lots of users mistakenly taking this as a ASP.NET specific question. Please note that my application is not a web application and I'm not using ASP.NET application (I'm using it's funtionality, that is available in .NET Core as well).
Recently, while configuring an Entity Framework DbContext lifetime in a Ninject DI, I have been digging through the .NET Core Dependency Injection, because it already has a functionality for registering DbContext and can be found here. The default context life time is ServiceLifetime.Scoped.
In the code peek, we can read that in the ASP.NET applications, "scoped" means:
scope is created around each server request
namespace Microsoft.Extensions.DependencyInjection
{
//
// Summary:
// Specifies the lifetime of a service in an Microsoft.Extensions.DependencyInjection.IServiceCollection.
public enum ServiceLifetime
{
//
// Summary:
// Specifies that a single instance of the service will be created.
Singleton = 0,
//
// Summary:
// Specifies that a new instance of the service will be created for each scope.
//
// Remarks:
// In ASP.NET Core applications a scope is created around each server request.
Scoped = 1,
//
// Summary:
// Specifies that a new instance of the service will be created every time it is
// requested.
Transient = 2
}
}
I'm trying to achieve a similar functionality in Ninject DI but it's really hard to state what would be the equivalent of scoped life time in Ninject, while speaking about .NET Core application (that isn't a web application!).
Ninject has that InRequestScope method, however it's only available for web applications, so it's really different from the .NET Core DI ServiceLifetime.Scoped setting.
Perhaps I would have to create some sort of a custom scope in Ninject, but still - I'm not really able to state, how to achieve exact the same scoped behaviour as in the .NET Core DI. To do that I need to be aware of how is the scoped life time working in context of a .NET Core application in .NET Core DI. My guess would be that there's one instance of a DbContext being created and is being disposed once the application quits.
Hence my questions:
How is .NET Core DI scope life time setting working and what is it's life cycle?
Is it possible to achieve a similar behaviour in Ninject DI?
How is .NET Core DI scope life time setting working and what is it's
life cycle?
.Net core internally works with class called ServiceScope. When new request is called (e.g. web request) new instance is created, with new service provider included. During request this service provider is used for dependency resolution. After request is finished, scope is disposed and also its service provider with its resolved services.
internal class ServiceScope : IServiceScope, IDisposable
{
private readonly Microsoft.Extensions.DependencyInjection.ServiceProvider _scopedProvider;
public ServiceScope(Microsoft.Extensions.DependencyInjection.ServiceProvider scopedProvider)
{
this._scopedProvider = scopedProvider;
}
public IServiceProvider ServiceProvider
{
get
{
return (IServiceProvider) this._scopedProvider;
}
}
public void Dispose()
{
this._scopedProvider.Dispose();
}
}
Is it possible to achieve a similar behaviour in Ninject DI?
As you have already noticed implementing custom scope is way to go. You can check how to do this in another answer:
Ninject - In what scope DbContext should get binded when RequestScope is meaningless?
EDIT:
Principle of .NET Core DI is the same like any other IOC container. It provides dependencies to your objects (MVC controllers etc.) by DI and controls its lifetime.
If you specify singleton lifetime for your DbContext than only one is
created, provided by DI when requested and hold in memory for
whole application/container lifetime.
If you specify transient you get new
one all the time DbContext is requested.
If you specify scoped,
lifetime of DbContext is bound to some disposable scope, which is created on the beggining of some logical request (http request in case of asp). When DbContext is
requested by DI for the first time, new one is created, hold in memory and you get always the same during
subsequent DI requests until the scope is disposed (with end of http request in case of asp) and DbContext with
it.
You can find similar parallel with TransactionScope. Here all the sqlCommands within the same TransactionScope are enlisted into the same sql transaction util the scope is disposed/committed.
There is extension method called InRequestScope, which is available in Ninject.Web.Common nuget package.
InRequestScope : https://github.com/ninject/Ninject.Web.Common/wiki/InRequestScope
You can correlate .net core and ninject DI methods
from https://github.com/ninject/Ninject/wiki/Object-Scopes

.net core 2.0 scoping issue with dbcontext

In .Net core 1.0 and 1.1 in my Services Collection I had:
services.AddDbContext<VisualJobsDbContext>();
...
...
services.AddScoped<IRecruiterRepository, RecruiterRepository>();
services.AddSingleton<IAccountRepository, AccountRepository>();
this seemed to work. Now I've gone to .net core 2.0 this has stopped working:
I've changed the above to :
services.AddDbContext<VisualJobsDbContext>(ServiceLifetime.Scoped);
...
...
services.AddScoped<IRecruiterRepository, RecruiterRepository>();
services.AddScoped<IAccountRepository, AccountRepository>();
I still receive the following error using swagger:
An unhandled exception occurred while processing the request.
InvalidOperationException: Cannot consume scoped service
FindaJobRepository.Interfaces.IAccountRepository from singleton
FindaJobServices.Interfaces.IAccountService
Does anybody have any ideas what else I can do?
IAccountService is a added as singleton and can't depend on a service with a shorter lifetime. IAccountRepository is a scoped service.
Probably you have a constructor with something like this:
public IAccountService(IAccountRepository accountRepository) {
}
Not sure how that ever worked, but essentially your issue is that you're trying to inject scoped services into a singleton, which based on the error is your AccountService.
Simply, if you need to use scoped services, the classes you inject them into must also be scoped. If you need the lifetime to be singleton, then your only option is use the service locator anti-pattern, where you instead inject IServiceProvider, and then create a scope around your operations:
using (var scope = _serviceProvider.CreateScope())
{
var context = scope.GetRequiredService<MyDbContext>();
// do something with context
}
Importantly, do not save the instances you retrieve from your scope to ivars, statics, etc. on your singleton class. These will disposed when the scope is disposed.

Dependency Injection in the ASP.NET 5 and Object Dispose

Can anybody help me to understand following in context to Dependency Injection in Asp.Net 5 and object dispose.
I need to understand if my Service implements IDispose interface ,who will call dispose method.
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IService, Service>();
services.AddScoped<IService, Service>();
services.AddSingleton<IService, Service>();
services.AddInstance<IService, Service>();
}
IServiceCollection contains the set of services available in your application. You defines the services you want to use and their lifetime, and the application will instantiate and dispose them for you.
There are 4 different lifetimes :
Transient
Transient lifetime services are created each time they are requested. This lifetime works best for lightweight, stateless service.
Scoped
Scoped lifetime services are created once per request.
Singleton
Singleton lifetime services are created the first time they are requested, and then every subsequent request will use the same instance. If your application requires singleton behavior, allowing the services container to manage the service’s lifetime is recommended instead of implementing the singleton design pattern and managing your object’s lifetime in the class yourself.
Instance
You can choose to add an instance directly to the services container. If you do so, this instance will be used for all subsequent requests (this technique will create a Singleton-scoped instance). One key difference between Instance services and Singleton services is that the Instance service is created in ConfigureServices, while the Singleton service is lazy-loaded the first time it is requested.
The asp.net 5 official documentation is great, take time to read it : http://docs.asp.net/en/latest/fundamentals/dependency-injection.html
The documentation doesn't mention how exactly the dependencies lifetimes are handled by the dependency injection service but if you search in the code, you will find the ServiceProvider class, who manages the lifetimes : ServiceManager class
To be a little more specific, when a scope is created, the service scope factory returns a new service scope, who is instanciated with a service provider. When the dependency injection service have to dispose a service, he calls the service scope's dispose method, who calls the service provider's dispose method.
How the service provider works ? He has all the service scopes in a property, named _resolvedServices, and all the transiant disposables in a property named _transientDisposables. When the dispose() method of the service provider is called, he loops on all the items he has in this two properties, and for each object calls his dispose method.
You have all the source code here : Dependency Injection source code

Categories

Resources