ASP.NET MVC+OWIN中随机出现DbContext已释放异常的原因排查
场景描述
我知道这个问题在Stack Overflow上可能属于宽泛问题,被关闭也正常,但还是想提交试试,不符合规范的话请见谅。
我正在开发一个基于OWIN的ASP.NET MVC应用,Startup类的ConfigureAuth方法配置如下:
public partial class Startup { public void ConfigureAuth(IAppBuilder app) { app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create); app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create); app.CreatePerOwinContext<ApplicationActionManager>(ApplicationActionManager.Create); app.CreatePerOwinContext<ApplicationApplicationManager>(ApplicationApplicationManager.Create); app.CreatePerOwinContext<ApplicationMenuManager>(ApplicationMenuManager.Create); app.CreatePerOwinContext<ReminderManager>(ReminderManager.Create); ... } }
现在遇到的问题是:执行数据库查询时会随机出现DbContext已释放(InvalidOperationException)异常,而且我没有手动调用过Dispose方法。我已经把所有手动实例化ApplicationDbContext的代码替换成HttpContext.Current.GetOwinContext().Get<ApplicationDbContext>(),但问题依旧存在。
遗憾的是没法提供更多细节,因为这个异常确实是随机触发的。
异常堆栈跟踪
堆栈1
System.ObjectDisposedException: ObjectContext实例已被释放,无法再用于需要连接的操作。 在 System.Data.Entity.Core.Objects.ObjectContext.ReleaseConnection() 在 System.Data.Entity.Core.Objects.ObjectContext.<ExecuteInTransactionAsync>d__156`1.MoveNext() --- 引发异常的上一位置的堆栈跟踪结束 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 在 System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<ExecuteAsyncImplementation>d__6`1.MoveNext() --- 引发异常的上一位置的堆栈跟踪结束 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 在 System.Data.Entity.Utilities.TaskExtensions.CultureAwaiter`1.GetResult() 在 System.Data.Entity.Core.Objects.ObjectQuery`1.<GetResultsAsync>d__43.MoveNext() --- 引发异常的上一位置的堆栈跟踪结束 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 在 System.Data.Entity.Utilities.TaskExtensions.CultureAwaiter`1.GetResult() 在 System.Data.Entity.Internal.LazyAsy
堆栈2
System.InvalidOperationException: 无法完成操作,因为DbContext已被释放。 在 System.Data.Entity.Internal.LazyInternalContext.InitializeContext() 在 System.Data.Entity.Internal.InternalContext.Initialize() 在 System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) 在 System.Data.Entity.Internal.Linq.InternalSet`1.Initialize() 在 System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext() 在 System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider() 在 System.Linq.Queryable.Where[TSource](IQueryable`1 source, Expression`1 predicate) 在 Test.ApplicationUserManager.GetLineMannagerByLogin(String login) [...] 在 Test.Controllers.BaseController.OnAuthorization(AuthorizationContext authContext) [...] 在 System.Web.Mvc.Controller.System.Web.Mvc.IAuthorizationFilter.OnAuthorization(AuthorizationContext filterContext) 在 System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor) 在 System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<BeginInvokeAction>b__19(AsyncCallback asyncCallback, Object asyncState) 在 System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.CallBeginDelegate(AsyncCallback
排查方向1:异步操作延迟执行导致的生命周期不匹配
从堆栈看异常出现在异步流程中,核心原因是请求结束后OWIN自动释放了DbContext,但后续异步代码仍在尝试使用它。OWIN的CreatePerOwinContext是按请求生命周期管理实例的,请求完成后会自动回收DbContext。如果存在以下情况就会触发问题:
- 异步方法中捕获了DbContext或未执行的
IQueryable,并在请求结束后才执行(比如后台任务、延迟回调) - 使用
async/await时未正确等待,导致后续代码在DbContext释放后才运行
修复建议:
- 确保所有依赖DbContext的异步操作都在请求生命周期内完成,不要将DbContext或未执行的查询传递到请求外
- 过滤器(如
OnAuthorization)中避免发起未等待的异步操作,业务允许的话改为同步实现
排查方向2:自定义Manager类的DbContext持有问题
检查所有通过CreatePerOwinContext创建的Manager类(如ApplicationUserManager)的Create方法:
- 是否自行创建DbContext而非从OWIN上下文获取?
- 是否在Manager内部缓存了DbContext,导致跨请求复用已释放的实例?
修复建议:
- 确保Manager类从OWIN上下文获取DbContext,示例代码:
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) { var dbContext = context.Get<ApplicationDbContext>(); var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(dbContext)); // 其他配置逻辑 return manager; }
- 不要在Manager类中存储DbContext的长期引用,每次操作都从OWIN上下文获取
排查方向3:请求提前终止导致DbContext被提前释放
如果请求因超时、客户端断开连接等原因提前终止,OWIN会提前释放DbContext,但此时可能还有后台代码在尝试使用它。
修复建议:
- 使用DbContext前增加状态检查:
var dbContext = HttpContext.Current.GetOwinContext().Get<ApplicationDbContext>(); if (dbContext == null || dbContext.Database.Connection.State == System.Data.ConnectionState.Closed) { throw new InvalidOperationException("数据库上下文不可用"); }
- 关键异步操作前检查客户端连接状态:
HttpContext.Current.Response.IsClientConnected
排查方向4:EF延迟加载触发的异常
如果实体类启用了延迟加载,在DbContext释放后访问未加载的导航属性,会直接触发异常(比如视图中访问控制器未提前加载的导航属性)。
修复建议:
- 查询时用
Include方法提前加载所需导航属性,避免延迟加载 - 不需要延迟加载的话,在DbContext构造函数中关闭:
this.Configuration.LazyLoadingEnabled = false;
内容的提问来源于stack exchange,提问作者Pine Code

