5

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?

2
  • Just register the DatabaseService and inject that into the controller. the framework will handle resolution of the service Commented Dec 5, 2017 at 0:09
  • Your DatabaseService looks exactly like a repository .... You figured it out already lol Commented Dec 5, 2017 at 0:15

1 Answer 1

3

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);
}
Sign up to request clarification or add additional context in comments.

7 Comments

@Nkosi...I saw how to do it that way, but got confused about actually injecting the DbContext. Thank you for clearing that up. Now what about if i create another class library project that will also use the DatabaseService? How do I inject the DbContext there? In your answer it seems the inject-ability is always coupled to the web app
@dinotom In this case the code is coupled to the ApplicationDbContext which is an implementation concern mainly associated with the View (web project) but if you abstracted that away and use the abstraction in the other projects then it doesn't matter any more. The dependent classes would be dependent on an abstraction that will be realized/resolved at run-time.
@dinotom I would suggest you do not make your code too reliant on the DbContext but rather on the services that wrap it. The DbContext is an implementation concern.
@Nkosi...would you mind looking at the Addendum to my question. Ty
@dinotom you basically reinforce my last two comments with that.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.