Cannot consume scoped service from singleton IHostedService
Today in this article, we will see how to resolve issue InvalidOperationException: Error while validating the service descriptor ‘ServiceType: <> Lifetime: Singleton ImplementationType: <>’: Cannot consume scoped service ‘<>’ from singleton ‘<>’.
Issue Description
You might get similar for different service type but the below discussed technique will help you those all-similar issues when used with their respective type.
ASP.NET Core using IHostedService gives runtime error,
InvalidOperationException: Error while validating the service descriptor ‘ServiceType: Microsoft.Extensions.Hosting.IHostedService Lifetime: Singleton ImplementationType: kafka_api_producer_consumer.TheCodeBuzzConsumer’: Cannot consume scoped service ‘SQLDBService.Context.EmployeeContext’ from singleton ‘Microsoft.Extensions.Hosting.IHostedService’.
Resolution
The reason being when we add AddHostedService to the application or API the Service Instance gets added as SingleTon instance.
As a good practice, EFCore DBContext should be set as a scoped instance.
In fact, EFCore using AddDBContext lets you add a scoped instance of DBContext to be the default.
It’s Important to consume scope services in scoped instances to avoid data corruption or threading issue.
While scope service instances are created once per request it is often recommended they are resolved using a scoped instance of services that use them. You might need to consider the below aspects also before resolving the issue.
Approach 1- Using ServiceScopeFactory to resolve Cannot consume scoped service error
class TheCodeBuzzConsumer : BackgroundService
{
private readonly ILogger<TheCodeBuzzConsumer> _logger;
private readonly EmployeeContext _employeeContext;
public TheCodeBuzzConsumer(ILogger<TheCodeBuzzConsumer> logger, IServiceScopeFactory factory)
{
_logger = logger;
_employeeContext = factory.CreateScope().ServiceProvider.GetRequiredService<EmployeeContext>();
}
The above code let you create Scoped instance of EmployeeContext and is able to work with the Database easily.
Approach 2- Using IServiceProvider to fix Cannot consume scoped service
We shall DI IServiceProvider using constructor injection as below,
class TheCodeBuzzConsumer : BackgroundService
{
private readonly ILogger<TheCodeBuzzConsumer> _logger;
private readonly EmployeeContext _employeeContext;
public TheCodeBuzzConsumer(ILogger<TheCodeBuzzConsumer> logger, IServiceProvider serviceProvider)
{
_logger = logger;
_employeeContext = serviceProvider.CreateScope().ServiceProvider.GetRequiredService<EmployeeContext>();
}
- By doing the above DBContext will be used with the lifetime configuration set up originally.
- This will also make sure Singleton instances are not created for the given services.
That’s all! Happy coding!
Does this help you fix your issue?
Do you have any better solutions or suggestions? Please sound off your comments below.
References:
Please bookmark this page and share it with your friends. Please Subscribe to the blog to receive notifications on freshly published(2024) best practices and guidelines for software design and development.
Thank you 🙂
Glad it helped you , thanks
I also want to say thank you for sharing your knowledge.
Ezúton is szeretném megköszönni, hogy megosztotta tudását.
Thank you for this great tip. Save day of head banging on wall.
Figuring out race condition with DBContext and services.
Hello Mubeen- Thanks. Glad it helped you solve the issue.
Llevaba 6 horas con ese problema, infinitas gracias desde Colombia
Hello Dany – good day! Glad to help you!
Thank you. Fixed issue for me.
Thanks Deepali- Glad it helped you!
thank you greetings from honduras
Thank you Carlos.