Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use EF DbConext outside of Controller?

I'm building ASP.Net app which is a simulator, lots of action will happens outside of Controller as separate threat, but I'm struggling to create DbContext connection outside of Controller. I know I could use OnConfiguring(DbContextOptionsBuilder optionsBuilder) but it doesn't look to my as most elegant way to do it.

I through something like this should work:

public class SimRepository : ISimRepository
{
    public IConfiguration _configuration;
    public DbContextOptionsBuilder _dbOptions;

    public SimRepository(IConfiguration configuration)
    {
        _configuration = configuration;

        _dbOptions = new DbContextOptionsBuilder();
        _dbOptions.UseSqlServer(_configuration.GetConnectionString("DefaultConnection"));
    }

    public void LatheIn()
    {
        using (AppDbContext db = new AppDbContext(_dbOptions.Options))
        {

        }
    }
}

but I receive this error:

Argument 1: cannot convert from Microsoft.EntityFrameworkCore.DbContextOptions' to Microsoft.EntityFrameworkCore.DbContextOptions<Simulator_Line.Server.AppDbContext>

In Startup:

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddDbContext<AppDbContext>(options => 
    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    services.AddMvc();

    //Enable use of appsettings.json outside of Startup.cs
    services.AddSingleton(Configuration);
    services.AddSingleton<IConfiguration>(Configuration);
}

If my approach is incorrect, I'm open to for changes.

EDIT

    public class LatheController : Controller
{
    private readonly AppDbContext _dbContext;
    private readonly SimRepository _simRrepo;

    public LatheController(AppDbContext dbContext, SimRepository latheRepo)
    {
        _dbContext = dbContext;
        _simRrepo = latheRepo;
    }

    [HttpGet]
    public IEnumerable<Lathe> GetLathes()
    {
        _simRrepo.LatheIn();



        return _dbContext.Lathes;
    }
}
like image 744
Whistler Avatar asked Dec 05 '25 14:12

Whistler


1 Answers

You have already registered the DbContext in the service collection. Just inject it into the dependent class so that it can be resolved when the dependent class is being resolved

public class SimRepository : ISimRepository {
    public readonly AppDbContext db;

    public SimRepository(AppDbContext db) {
        this.db = db;
    }

    public void LatheIn() {
        //...use db
    }
}

Update

You can create a factory

public interface IAppDbContextFactory {
    AppDbContext Create();
}

Which be used for creating instances as needed

public class SimRepository : ISimRepository {
    public readonly IAppDbContextFactory factory;

    public SimRepository(IAppDbContextFactory factory) {
        this.factory = factory;
    }

    public void LatheIn() {
        using (AppDbContext db = factory.Create()) {
            //...use db
        }
    }
}

Factory implementation could look like

public class AppDbContextFactory : IAppDbContextFactory {
    private readonly IServiceProvider servideProvider;

    public AppDbContextFactory(IServiceProvider servideProvider) {
        this.serviceProvider = serviceProvider;
    }

    public AppDbContext Create() {
        return serviceProvider.GetService<AppDbContext>();
    }
}

Make sure to register the your types with the service collection.

public void ConfigureServices(IServiceCollection services) {
    // Add framework services.
    services.AddDbContext<AppDbContext>(options => 
    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    services.AddMvc();

    //Enable use of appsettings.json outside of Startup.cs
    services.AddSingleton(Configuration);
    services.AddSingleton<IConfiguration>(Configuration);

    services.AddSingleton<IAppDbContextFactory, AppDbContextFactory>();
    services.AddTransient<ISimRepository, SimRepository>();
}

So that it can be used where needed

public class SomeController : Controller {
    private readonly ISimRepository simRepository;
    public SomeController(ISimRepository simRepository) {
        this.simRepository = simRepository;
    }

    public IActionResult SomeAction() {
        simRepository.LatheIn();
        return Ok();
    }
}
like image 68
Nkosi Avatar answered Dec 07 '25 04:12

Nkosi