DbContext Dependency Injection outside of MVC project

asp.net-core asp.net-core-2.0 asp.net-mvc dependency-injection entity-framework-6

Question

I have a C# solution with two projects, ProductStore.Web and ProductStore.Data, both targeting .NET Core 2.0.

I have my HomeController and CustomerRepository as follows (I've set it up in the HomeController for speed, customer creation will be in the customer controller, but not yet scaffold-ed it out):

namespace ProductStore.Web.Controllers
{
    public class HomeController : Controller
    {
        private readonly DatabaseContext _context;

        public HomeController(DatabaseContext context)
        {
            _context = context;
        }
        public IActionResult Index()
        {
            ICustomerRepository<Customer> cr = new CustomerRepository(_context);
            Customer customer = new Customer
            {
                // customer details
            };
            //_context.Customers.Add(customer);
            int result = cr.Create(customer).Result;
            return View();
        }
    }
}

namespace ProductStore.Data
{
    public class CustomerRepository : ICustomerRepository<Customer>
    {
        DatabaseContext _context;
        public CustomerRepository(DatabaseContext context)
        {
            _context = context;
        }
    }
}

Dependency Injection resolves _context automatically inside the controller. I am then passing the context as a parameter for CustomerRepository which resides in ProductStore.Data.

My question is two fold:

  1. Is this best practice (passing the context from controller to CustomerRepository)
  2. If not best practice, can I access context via IServiceCollection services in a similar way to how the DatabaseContext is inserted into services in my application StartUp.cs class...

I feel like I shouldn't have to pass the context over, CustomerRepository should be responsible for acquiring the context.

FYI, relatively new to MVC and brand new to Entity Framework and Dependency Injection

Thanks

1
3
10/3/2017 10:01:36 PM

Accepted Answer

You don't need to pass context to controller to be able to use the context registered in services inside repository. The way I prefer to do that, is the following. Inject context into repository and then inject repository into controller. Using the Microsoft Dependency Injection Extension in for .Net Core it will look like this

// Service registrations in Startup class
public void ConfigureServices(IServiceCollection services)
{
    // Also other service registrations
    services.AddMvc();
    services.AddScoped<DatabaseContext, DatabaseContext>();
    services.AddScoped<ICustomerRepository<Customer>, CustomerRepository>();
}

// Controller
namespace ProductStore.Web.Controllers
{
    public class HomeController : Controller
    {
        private readonly ICustomerRepository _customerRepository;

        public HomeController(ICustomerRepository customerRepository)
        {
            _customerRepository = customerRepository;
        }
        public IActionResult Index()
        {
            Customer customer = new Customer
            {
                // customer details
            };
            //_context.Customers.Add(customer);
            int result = _customerRepository.Create(customer).Result;
            return View();
        }
    }
}

//Repository
namespace ProductStore.Data
{
    public class CustomerRepository : ICustomerRepository<Customer>
    {
        DatabaseContext _context;
        public CustomerRepository(DatabaseContext context)
        {
            _context = context;
        }
    }
}

After this when DependencyResolver tries to resolve ICustomerRepository to inject into the HomeController he sees, that the registered implementation of ICustomerRepository (in our case CustomerRepository) has one constructor which needs DatabaseContext as a parameter and DependencyResolver trying to to get registered service for DatabaseContext and inject it into CustomerRepository

4
10/4/2017 9:37:28 PM

Popular Answer

If you define your repository in your ConfigureServices method, you won't need to inject the DbContext into controller, just the repository:

public void ConfigureServices(IServiceCollection services)
{
  services.AddDbContext<DbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        
  services.AddScoped(typeof(ICustomerRepository<>), typeof(CustomerRepository<>));
}

Then you can just simply inject the repository into controller:

public class HomeController : Controller
{
  private readonly ICustomerRepository _customerRepository;

  public HomeController(ICustomerRepository customerRepository)
  {
      _customerRepository = customerRepository;
  }
  ...
}

The dependency injector takes care of injecting DbContext into your repository.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow