ASP.NET MVC使用Ninject注入UserManager到控制器报错解决
问题根因
当前错误来自两套ApplicationUserManager生命周期管理逻辑的冲突:
- 你已经在Owin管道的
ConfigureAuth中通过CreatePerOwinContext配置了按请求创建ApplicationUserManager实例 - 同时给
UserController写了带ApplicationUserManager参数的构造函数,Ninject会尝试自行构造ApplicationUserManager实例注入,但Ninject中缺少两类关键绑定:一是控制器依赖的是ApplicationUserManager子类,你只绑定了父类UserManager<ApplicationUser>;二是UserStore<ApplicationUser>依赖ApplicationDbContext,你没有注册对应绑定,最终导致IUserStore激活失败。
另外你的业务代码还有一处逻辑遗漏:Users action构造完usersRoles列表后,没有将模型传递给视图。
修复方案
二选一即可,禁止混用两套实例管理逻辑,优先选择方案1,和ASP.NET Identity默认模板逻辑兼容,改造成本最低。
方案1:沿用Owin管理身份实例,移除Ninject对相关类型的构造干预
- 打开
NinjectWebCommon.cs,删除RegisterServices方法中以下两条和身份组件相关的绑定:
kernel.Bind<IUserStore<ApplicationUser>>().To<UserStore<ApplicationUser>>(); kernel.Bind<UserManager<ApplicationUser>>().ToSelf();
- 修改
UserController,添加无参构造函数,移除对Ninject注入UserManager的依赖,直接通过已有的属性逻辑从Owin上下文获取实例,同时补全视图传参:
public class UserController : Controller { private ApplicationUserManager _userManager; public UserController() { } public ApplicationUserManager UserManager { get { return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>(); } private set { _userManager = value; } } public ActionResult Users() { var users = UserManager.Users.ToList(); var usersRoles = new List<UserIndexResponse>(); foreach (var user in users) { var roles = UserManager.GetRoles(user.Id); var role = roles.FirstOrDefault(); if (!string.IsNullOrEmpty(role)) { var usersRole = new UserIndexResponse() { Id = user.Id, Email = user.Email, LockedOutDue = user.LockoutEndDateUtc, Role = role }; usersRoles.Add(usersRole); } } // 补全模型传参 return View(usersRoles); } }
方案2:全量用Ninject管理身份相关实例(不推荐)
注意:该方案需要自行维护所有Identity组件的配置,和默认模板兼容性差,无特殊需求不要采用。
如果坚持使用构造函数注入UserManager,需要补全所有依赖绑定,同时移除Owin中对应的PerRequest实例注册:
- 在
RegisterServices中补全ApplicationDbContext、IUserStore<ApplicationUser>、ApplicationUserManager的请求级绑定,注意要把原来ApplicationUserManager.Create静态方法里的所有配置(密码校验规则、用户验证规则、短信/邮件服务等)迁移到Ninject的实例初始化逻辑中 - 删除
ConfigureAuth中app.CreatePerOwinContext(ApplicationDbContext.Create);、app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);、app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);三条注册 - 同步修改
ApplicationSignInManager的获取逻辑,全部改为Ninject注入
该方案改动量大,容易遗漏Identity的相关配置。
内容的提问来源于stack exchange,提问作者ELOL
相关产品推荐
相关产品推荐

