Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to inject DbContext into repository constructor in ASP.NET core

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)?

like image 222
GDiff94 Avatar asked May 30 '19 18:05

GDiff94


People also ask

How to inject dbcontext into irepository in Entity Framework?

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

What is dbcontext in ASP NET Core?

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.

Can the dbcontextoptions constructor be called explicitly?

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.

How do I use dbcontext with a dependency injection container?

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.


Video Answer


1 Answers

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>();
like image 141
Nkosi Avatar answered Nov 01 '22 10:11

Nkosi