Within ConfigureServices
I have
services.AddDbContext<MyContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
as well as
services.AddSingleton<IMyModel>(s =>
{
var dbContext = s.GetService<MyContext>();
var lastItem= dbContext.Items.LastOrDefault();
return new MyModel(lastItem);
});
But s.GetService<MyContext>()
throws an error:
Cannot resolve scoped service 'MyContext' from root provider.
How can I achieve that? I don't want to inject MyDbContext
in MyModel
contructor as it is in a library which should have no reason to know about Entity Framework
.
1 Answer. First, DbContext is a lightweight object; it is designed to be used once per business transaction. Making your DbContext a Singleton and reusing it throughout the application can cause other problems, like concurrency and memory leak issues. And the DbContext class is not thread safe.
EF and EF Core DbContext types implement IDisposable . As such, best practice programming suggests that you should wrap them in a using() block (or new C# 8 using statement). Unfortunately, doing this, at least in web apps, is generally a bad idea.
This example registers a DbContext subclass called ApplicationDbContext as a scoped service in the ASP.NET Core application service provider (a.k.a. the dependency injection container). The context is configured to use the SQL Server database provider and will read the connection string from ASP.NET Core configuration.
You should almost never consume scoped service or transient service from a singleton. You should also avoid consuming transient service from a scoped service. What is happening when you consume scoped service from a singleton service is known as a captive dependency.
AddDbContext
defaults to using a scoped lifestyle:
Scoped lifetime services (AddScoped) are created once per client request (connection).
The reason an error is being thrown is that you're attempting to obtain an instance of MyContext
from outside of a request. As the error message suggests, it is not possible to obtain a scoped service from the root IServiceProvider
.
For your purposes, you can create a scope explicitly and use that for your dependency resolution, like so:
services.AddSingleton<IMyModel>(sp =>
{
using (var scope = sp.CreateScope())
{
var dbContext = scope.ServiceProvider.GetService<MyContext>();
var lastItem = dbContext.Items.LastOrDefault();
return new MyModel(lastItem);
}
});
This code above creates a scoped IServiceProvider
that can be used for obtaining scoped services.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With