DbContext Dependency Injection outside of MVC proj

2019-05-11 22:13发布

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条回答
\"骚年 ilove
2楼-- · 2019-05-11 22:46

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.

查看更多
放我归山
3楼-- · 2019-05-11 22:47

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楼-- · 2019-05-11 22:50

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.

查看更多
登录 后发表回答