Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting DbContext to class library project in same Asp.Net Core 2 solution

Something that used to be relatively easy, isn't so anymore. Of the dozens of times I've searched, I rarely find an answer to this situation, which I cannot believe is anything other than prevalent in most project structures.

I have the standard Core 2.0 Web app, and for now, for simplicity sake, an Infrastructure project and a unit test project. I have a good idea how to accomplish the test scenario since the test project doesn't run asp.net and I have a great video tutorial on how to accomplish it.

The problem lies with getting access to the DbContext in my infrastructure project. (.Net Core class library)

The DbContext sets up perfectly fine in Startup

var connString = Configuration.GetSection("ApplicationConfiguration:ConnectionStrings:DefaultConnection").Value;
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(connString));

And in a controller I can access it

private ApplicationDbContext _context;
private IConfiguration Configuration { get; set; }

public HomeController(IConfiguration configuration, ApplicationDbContext context)
{
    _context = context;
    Configuration = configuration;
}

public IActionResult Index()
{
     // gets users from the DI injected context in the controller
    var users = _context.AppUsers.ToList();

    // if GetUsers is defined statically, this doesn't work because the injected context is always null
    //var diUsers = DatabaseService.GetUsers():

    // making it non-static and newing it up works, but defeats the purpose because you are passing the context, asp.net is not injecting it
    var ds = new DatabaseService(_context);
    var diUsers = ds.GetUsers();

    var svm = SettingsViewModel();

    return View(svm);
}

DatabaseService

private ApplicationDbContext _context;
//this is the constructor for DatabaseService class
public DatabaseService(ApplicationDbContext context)
{
    _context = context;
}

public List<ApplicationUser> GetUsers()
{
    var users = _context.AppUsers.ToList();
    return users;
}

Yes, I know I should be using a repository and I will once I get this figured out correctly. How do I set up my classes in the Infrastructure project so I have the injected DbContext created at Startup and not have to pass it as a parameter.

Addendum:

Using the answer provided by Nkosi, I can inject the data service in the controller and use it.

But if I have a separate Infrastructure project (Asp.net core 2 class library), which implements my repository and UoW

 public class GenericRepository<T> : IRepository<T> where T : class
{
    public GenericRepository()
    {

    }
    //rest of code removed
}

How can I get the DbContext injected there? Do I need to create an Interface, IDbContext, to wrap DbContext, and register that in startup?

like image 244
dinotom Avatar asked Oct 17 '22 02:10

dinotom


1 Answers

Assuming you have the following for your service

public interface IDatabaseService {
    List<ApplicationUser> GetUsers();
    //...
}

public class DatabaseService : IDatabaseService {

    public DatabaseService(ApplicationDbContext context) {
        //...code removed for brevity
    }

    //...code removed for brevity
}

The service explicitly depends on the ApplicationDbContext which will be injected when the implementation is being resolved from the service container.

Register the service in Startup.ConfigureServices

var connString = Configuration.GetSection("ApplicationConfiguration:ConnectionStrings:DefaultConnection").Value;
services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(connString));
services.AddScoped<IDatabaseService, DatabaseService>();

And refactor the controller to explicitly depend on the service

private IDatabaseService ds;
private IConfiguration Configuration { get; set; }

public HomeController(IConfiguration configuration, IDatabaseService ds) {
    this.ds = ds;
    Configuration = configuration;
}

public IActionResult Index() {
    var diUsers = ds.GetUsers();

    var svm = SettingsViewModel();

    return View(svm);
}
like image 57
Nkosi Avatar answered Oct 20 '22 08:10

Nkosi