ASP.NET Core中UnitOfWork模式迁移与依赖注入异常解决指引
这个问题我之前帮不少开发者解决过——本质就是ASP.NET Core的依赖注入(DI)容器不会自动识别自定义服务类,必须显式把你的AccountProvider注册到容器里,才能在控制器中正常注入。咱们一步步来搞定:
1. 先确认AccountProvider的构造函数依赖
首先得保证你的AccountProvider构造函数的依赖项已经被正确注册(你提到已经在Startup里注册了LoginContext,这部分应该没问题)。举个典型的AccountProvider构造函数例子,它应该是依赖LoginContext的:
public class AccountProvider : IUnitOfWork { private readonly LoginContext _dbContext; // 假设你有仓储实例 private GenericRepository<User> _userRepository; // 构造函数注入LoginContext,DI容器会自动解析这个依赖 public AccountProvider(LoginContext dbContext) { _dbContext = dbContext; } // 实现IUnitOfWork的方法,比如SaveChanges、获取仓储的方法... public void SaveChanges() => _dbContext.SaveChanges(); public GenericRepository<User> UserRepository => _userRepository ??= new GenericRepository<User>(_dbContext); }
如果你的构造函数还有其他依赖,比如特定的仓储类,也要确保这些依赖已经注册到DI容器中。
2. 把AccountProvider注册到DI容器
根据你的.NET Core版本不同,注册位置分为两种情况:
情况1:.NET 5及更早版本(使用Startup.cs)
在Startup.cs的ConfigureServices方法中,添加对AccountProvider的注册。推荐注册接口与实现类的映射(符合依赖倒置原则),当然也可以直接注册具体类:
public void ConfigureServices(IServiceCollection services) { // 你已经注册的LoginContext(确保连接字符串名称匹配) services.AddDbContext<LoginContext>(options => options.UseSqlServer(Configuration.GetConnectionString("LoginConnection"))); // 核心步骤:注册IUnitOfWork和AccountProvider的映射 // 用Scoped生命周期(和DbContext默认生命周期一致,推荐) services.AddScoped<IUnitOfWork, AccountProvider>(); // 如果你非要直接注入AccountProvider类本身,也可以添加这行 // services.AddScoped<AccountProvider>(); services.AddControllersWithViews(); }
情况2:.NET 6+版本(使用Program.cs)
在Program.cs的WebApplication构建流程中添加注册:
var builder = WebApplication.CreateBuilder(args); // 注册LoginContext builder.Services.AddDbContext<LoginContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("LoginConnection"))); // 注册IUnitOfWork与AccountProvider builder.Services.AddScoped<IUnitOfWork, AccountProvider>(); // 或者直接注册AccountProvider // builder.Services.AddScoped<AccountProvider>(); builder.Services.AddControllersWithViews(); var app = builder.Build(); // 后续的中间件配置...
3. 修改控制器的注入方式(推荐最佳实践)
为了让代码更灵活、符合面向接口编程的原则,建议控制器中注入IUnitOfWork接口,而不是具体的AccountProvider类:
public class AccountController : Controller { private readonly IUnitOfWork _unitOfWork; // 注入IUnitOfWork,DI容器会自动解析为AccountProvider实例 public AccountController(IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; } // 比如登录方法示例 [HttpPost] public IActionResult Login(LoginViewModel model) { var user = _unitOfWork.UserRepository.Get(u => u.Username == model.Username); // 后续逻辑... return View(); } }
如果你坚持要直接注入AccountProvider,那控制器构造函数改成public AccountController(AccountProvider accountProvider)即可,前提是你已经在DI容器中注册了AccountProvider。
4. 最后验证连接字符串配置
虽然你提到已经配置了,但还是确认下appsettings.json中的连接字符串格式正确,且名称和注册LoginContext时用的一致:
{ "ConnectionStrings": { "LoginConnection": "Server=你的数据库服务器;Database=LoginDB;Trusted_Connection=True;TrustServerCertificate=True;" } }
做完这些步骤,再运行项目,那个InvalidOperationException应该就消失了——核心就是让DI容器知道你的AccountProvider类该怎么创建和注入。
内容的提问来源于stack exchange,提问作者Majid821

