问题
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:
- Is this best practice (passing the context from controller to CustomerRepository)
- 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:
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
回答2:
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.
回答3:
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.
来源:https://stackoverflow.com/questions/46554107/dbcontext-dependency-injection-outside-of-mvc-project