如何从Unity容器解析OwinContext?MVC5中Unity注入UserManager报错
嘿,这个问题我之前在搭建MVC5+Unity+Identity的项目时踩过一模一样的坑!Cannot access a disposed object这个错误本质上是Unity的生命周期管理和Identity框架的对象存活逻辑不兼容导致的,尤其是ApplicationUserManager这种需要在整个请求周期内保持可用的服务。下面是我当时解决问题的几个关键步骤:
1. 修正Unity容器的服务注册生命周期
首先要确保你在UnityConfig.cs里给Identity相关服务注册的是**PerRequestLifetimeManager**(每个请求对应一个实例),而不是默认的瞬时(Transient)或单例(Singleton)模式。错误的生命周期会导致对象被提前释放。
正确的注册代码示例:
public static void RegisterComponents() { var container = new UnityContainer(); // 核心:给Identity相关服务配置请求级生命周期 container.RegisterType<ApplicationUserManager>(new PerRequestLifetimeManager()); container.RegisterType<ApplicationSignInManager>(new PerRequestLifetimeManager()); container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>( new InjectionConstructor(typeof(ApplicationDbContext)), new PerRequestLifetimeManager() ); container.RegisterType<ApplicationDbContext>(new PerRequestLifetimeManager()); container.RegisterType<IAuthenticationManager>( new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication) ); DependencyResolver.SetResolver(new UnityDependencyResolver(container)); }
2. 重构AccountController的注入方式
很多时候问题出在控制器里还在使用传统的懒加载属性获取UserManager,而不是完全依赖Unity的构造函数注入。要把手动获取的逻辑删掉,改用构造函数注入实例:
public class AccountController : Controller { private readonly ApplicationUserManager _userManager; private readonly ApplicationSignInManager _signInManager; // 构造函数注入,让Unity全权管理实例生命周期 public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager) { _userManager = userManager; _signInManager = signInManager; } // 注释掉这种手动从OwinContext获取的懒加载属性,避免生命周期冲突 // public ApplicationUserManager UserManager // { // get // { // return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>(); // } // } // 你的登录Action示例 [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) { if (!ModelState.IsValid) { return View(model); } // 直接使用注入的_userManager,无需手动创建或释放 var user = await _userManager.FindByNameAsync(model.UserName); if (user == null) { ModelState.AddModelError("", "Invalid username or password."); return View(model); } // 后续登录逻辑... } }
3. 禁止手动释放注入的实例
检查代码中是否存在手动调用_userManager.Dispose()或者用using块包裹注入实例的情况——这会导致Unity管理的实例被提前释放,后续访问时就会抛出已释放对象的错误。
❌ 错误示例:
// 不要手动Dispose Unity注入的实例 using(var manager = _userManager) { var user = manager.FindByName(username); }
✅ 正确做法:让Unity在请求结束时自动释放PerRequest生命周期的实例,不要手动干预。
4. 验证Owin与Unity的生命周期同步
如果你的ApplicationDbContext也是由Unity管理的,一定要确保它的生命周期同样是PerRequestLifetimeManager——因为UserStore依赖DbContext,DbContext提前释放会直接导致UserManager无法正常工作。
内容的提问来源于stack exchange,提问作者Junior

