ASP.NET MVC5中如何正确注入Repository、UnitOfWork及服务提供者到控制器?
Great question! Let’s walk through exactly how to set up dependency injection for your repositories, Unit of Work, and services in an ASP.NET MVC5 app. Since MVC5 doesn’t come with built-in DI, we’ll use a popular container like Autofac (the same logic applies to Unity, Ninject, or others—we’ll stick with Autofac here because it’s widely used and straightforward).
First, install the required NuGet package for Autofac integration with MVC5:
Install-Package Autofac.Mvc5
Next, create a configuration class to register your dependencies. Let’s call it AutofacConfig.cs in your root project:
using Autofac; using Autofac.Integration.Mvc; using YourApp.Data; using YourApp.Data.Repositories; using YourApp.Services; using System.Web.Mvc; namespace YourApp { public static class AutofacConfig { public static void RegisterDependencies() { var builder = new ContainerBuilder(); // Register all MVC controllers in your assembly builder.RegisterControllers(typeof(MvcApplication).Assembly); // Register your generic repository: maps IRepository<T> to Repository<T> builder.RegisterGeneric(typeof(Repository<>)) .As(typeof(IRepository<>)) .InstancePerRequest(); // One instance per HTTP request // Register Unit of Work (replace with your concrete implementation) builder.RegisterType<UnitOfWork>() .As<IUnitOfWork>() .InstancePerRequest(); // Register your service classes (example: user and product services) builder.RegisterType<UserService>() .As<IUserService>() .InstancePerRequest(); builder.RegisterType<ProductService>() .As<IProductService>() .InstancePerRequest(); // Register your DbContext (critical for repository/Unit of Work access) builder.RegisterType<YourAppDbContext>() .InstancePerRequest(); // Build the container and set it as MVC's dependency resolver var container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); } } }
Now, hook this up in Global.asax.cs so it runs when your app starts:
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); // Add this line to register DI dependencies AutofacConfig.RegisterDependencies(); }
Your Unit of Work should wrap your repositories and manage the DbContext lifecycle. Here’s a typical implementation:
public interface IUnitOfWork : IDisposable { IRepository<User> Users { get; } IRepository<Product> Products { get; } int SaveChanges(); } public class UnitOfWork : IUnitOfWork { private readonly YourAppDbContext _context; private IRepository<User> _userRepo; private IRepository<Product> _productRepo; // Inject DbContext via constructor (DI will handle this) public UnitOfWork(YourAppDbContext context) { _context = context; } // Lazy-load repositories to avoid unnecessary instantiation public IRepository<User> Users => _userRepo ??= new Repository<User>(_context); public IRepository<Product> Products => _productRepo ??= new Repository<Product>(_context); public int SaveChanges() { return _context.SaveChanges(); } public void Dispose() { _context.Dispose(); } }
MVC5 supports constructor injection once you’ve set up the dependency resolver. Simply declare your dependencies in the controller’s constructor—Autofac will automatically resolve them:
public class UserController : Controller { private readonly IUserService _userService; private readonly IUnitOfWork _unitOfWork; // Constructor injection: dependencies are explicit and testable public UserController(IUserService userService, IUnitOfWork unitOfWork) { _userService = userService; _unitOfWork = unitOfWork; } public ActionResult Index() { var users = _userService.GetAllActiveUsers(); return View(users); } [HttpPost] public ActionResult Create(UserViewModel model) { if (ModelState.IsValid) { var newUser = new User { Name = model.FullName, Email = model.EmailAddress }; _unitOfWork.Users.Add(newUser); _unitOfWork.SaveChanges(); return RedirectToAction("Index"); } return View(model); } }
If you’re using a service layer, you can inject repositories or Unit of Work directly into your services:
public interface IUserService { IEnumerable<User> GetAllActiveUsers(); } public class UserService : IUserService { private readonly IRepository<User> _userRepository; public UserService(IRepository<User> userRepository) { _userRepository = userRepository; } public IEnumerable<User> GetAllActiveUsers() { return _userRepository.Find(u => u.IsActive); } }
- InstancePerRequest: Always use this scope for DbContext, repositories, and Unit of Work—they aren’t thread-safe, so one instance per request avoids race conditions.
- Constructor Injection Over Property Injection: Constructor injection makes dependencies explicit, making your code easier to test and understand. Avoid property injection unless you have a specific reason.
- Lazy Loading Repositories: As shown in the Unit of Work example, lazy-load repositories to avoid creating unnecessary instances when they aren’t needed.
- Testability: With DI, you can easily mock your repositories/services in unit tests (e.g., using Moq) without relying on a real database.
内容的提问来源于stack exchange,提问作者Junior

