4

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

3
  • Why not inject context directly into repository? Commented Oct 3, 2017 at 22:03
  • @RubenVardanyan thats what I'm asking. I know I could just create a new context object from within repository, but if the context already exists within my applications services, I feel I should be re-using it? Commented Oct 3, 2017 at 22:07
  • see answer below Commented Oct 3, 2017 at 22:18

3 Answers 3

6

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

Sign up to request clarification or add additional context in comments.

3 Comments

@Yaser, yes I missed the part of generics. But in this case only the interface is generic and not implementation. So, this approach should work.
@Yaser there was extra > symbol in snippest, that was the reason
Isn't scoped a better lifetime to use for dbcontexts?
3

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.

Comments

1

1. Is this best practice (passing the context from controller to CustomerRepository)

I think you're looking for something like a "Unit of Work" pattern.

Microsoft has written a tutorial about creating one here.

I would also inject the repository in your controller instead of your context.

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...

If I understand you correctly, than yes, you can. Also add the CustomerRepository to the services in your StartUp.cs so you can use it in your controller.

Mabye this tutorial from Microsoft will also help you.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.