在Unit Of Work设计模式中能否使用依赖注入?是否有必要?
Absolutely! You can absolutely use dependency injection (DI) with the Unit of Work (UoW) pattern here—and in most real-world scenarios, you should. The Microsoft docs example uses manual initialization for simplicity, but integrating DI makes your code more flexible, testable, and aligned with modern software design principles like SOLID.
How to Implement DI with Unit of Work
Here's a step-by-step breakdown for ASP.NET Core (the approach applies to other DI containers too):
1. Register Dependencies in Your DI Container
First, register your DbContext and repository interfaces/implementations with the container. We use scoped lifetimes here because UoW and DbContext instances are typically tied to a single request:
// In Program.cs (ASP.NET Core 6+) builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); // Register repositories (interface -> implementation) builder.Services.AddScoped<IProductRepository, ProductRepository>(); builder.Services.AddScoped<IOrderRepository, OrderRepository>(); // Register the Unit of Work builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();
2. Refactor the UnitOfWork Class to Accept Injected Dependencies
Instead of manually initializing the DbContext and repositories, we'll inject them via the constructor. This lets the DI container handle instance creation and lifecycle management:
public interface IUnitOfWork { IProductRepository Products { get; } IOrderRepository Orders { get; } Task<int> SaveChangesAsync(); } public class UnitOfWork : IUnitOfWork, IDisposable { private readonly AppDbContext _dbContext; private readonly IProductRepository _productRepo; private readonly IOrderRepository _orderRepo; // Inject dependencies directly public UnitOfWork(AppDbContext dbContext, IProductRepository productRepo, IOrderRepository orderRepo) { _dbContext = dbContext; _productRepo = productRepo; _orderRepo = orderRepo; } // Expose repositories via the interface public IProductRepository Products => _productRepo; public IOrderRepository Orders => _orderRepo; public async Task<int> SaveChangesAsync() { return await _dbContext.SaveChangesAsync(); } public void Dispose() { _dbContext.Dispose(); } }
Note: Your repository implementations should also accept the DbContext via their own constructors, rather than having the UoW pass it along. This keeps each component focused on its own responsibility.
3. Inject IUnitOfWork Into Your Controllers/Services
Now you can inject the IUnitOfWork interface wherever you need to use it—no more manual initialization:
public class ProductsController : Controller { private readonly IUnitOfWork _unitOfWork; public ProductsController(IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; } public async Task<IActionResult> Index() { var products = await _unitOfWork.Products.GetAllAsync(); return View(products); } }
Is DI Necessary?
There are rare cases where you might skip DI:
- Tiny, single-purpose applications: If you're building a super simple app with only one or two repositories, no plans to write unit tests, and no need to swap implementations, the overhead of DI might not be worth it. The manual approach from the docs could work fine here.
But for almost all other scenarios, DI is highly recommended. It:
- Makes unit testing easier (you can inject mock repositories instead of real ones)
- Reduces tight coupling between components
- Lets you easily change implementations (e.g., switch from SQL Server to SQLite) without rewriting core logic
- Aligns with industry best practices for maintainable code
内容的提问来源于stack exchange,提问作者Lama Sonmez

