I am writing my first ASP.NET Core Web API and am trying to work out how to inject my DbContext object into my repository constructor. I followed the EF part of this tutorial where the DbContext is registered to the service collection via services.AddDbContext<DbContext>
and services.GetRequiredService<DbContext>()
is used to initialize the database values.
public class Startup
{
public IConfiguration Configuration {
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSingleton<IItemRepository, ItemRepository>();
services.AddSingleton<IUserRepository, UserRepository>();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
});
services.AddDbContext<RAFYCContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}
}
public class Program
{
public static void Main(string[] args)
{
//CreateWebHostBuilder(args).Build().Run();
IWebHost host = CreateWebHostBuilder(args).Build();
using (IServiceScope scope = host.Services.CreateScope())
{
IServiceProvider services = scope.ServiceProvider;
try
{
RAFYCContext context = services.GetRequiredService<RAFYCContext>();
DbInitializer.Initialize(context);
}
catch (Exception ex)
{
ILogger logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while seeding the database.");
}
}
host.Run();
}
}
I am able to inject the DbContext into the Controller and then call a repository method to assign it to the UserRepository:
public class UserController : ControllerBase
{
IUserRepository _userRepo;
public UserController(IUserRepository userRepo, RAFYCContext context)
{
_userRepo = userRepo;
_userRepo.SetDbContext(context);
}
}
public class UserRepository : IUserRepository
{
public RAFYCContext _context;
public UserRepository() { }
public void SetDbContext(RAFYCContext context)
{
this._context = context;
}
}
This works, however I would like to inject the DbContext into the constructor of my repository rather than assigning it in the Controller constructor after instantiation, like below:
[Route("api/[controller]")]
[ApiController]
public class UserController : ControllerBase
{
IUserRepository _userRepo;
public UserController(IUserRepository userRepo)
{
_userRepo = userRepo;
}
}
public class UserRepository : IUserRepository
{
RAFYCContext _context;
public UserRepository(RAFYCContext context)
{
_context = context;
}
}
With this code I get the following error:
InvalidOperationException: Cannot consume scoped service 'RAFYC.MobileAppService.Models.RAFYCContext' from singleton 'RAFYC.MobileAppService.Repositories.IUserRepository'
Does anyone know if this is possible with ASP.NET Core (2.2)?
Create an ASP.Net core project to which we will use IRepository IRepository implementation will use EF Core Data Project (i.e. MyApi.Data is EF core data project that contains all Entity classes and DbContext Class) we will register DbContext to DI container so that DbContext is injected into IRepository implementation
ASP.NET Core - DBContext. Logically, a DBContext maps to a specific database that has a schema that the DBContext understands. And on that DBContext class, you can create properties that are type DbSet<T>. The generic type parameter T will be a type of entity like Employee is an entity in the FirstAppDemo application.
The DbContextOptions can be created and the constructor can be called explicitly: Some application types (e.g. ASP.NET Core Blazor) use dependency injection but do not create a service scope that aligns with the desired DbContext lifetime.
EF Core supports using DbContext with a dependency injection container. Your DbContext type can be added to the service container by using the AddDbContext<TContext> method. AddDbContext<TContext> will make both your DbContext type, TContext, and the corresponding DbContextOptions<TContext> available for injection from the service container.
AddDbContext
adds a DbContext
as scoped by default, which would cause problems with the singleton repositories.
It's dangerous to resolve a scoped service from a singleton. It may cause the service to have incorrect state when processing subsequent requests.
Reference Dependency injection in ASP.NET Core: Service lifetimes
I would suggest adding the repositories as scoped as well if possible.
services.AddScoped<IItemRepository, ItemRepository>();
services.AddScoped<IUserRepository, UserRepository>();
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