ASP.NET MVC5 Owin应用修改Autofac配置后,应用关闭时容器提前销毁导致清理逻辑失效的问题排查与咨询
ASP.NET MVC5 Owin应用修改Autofac配置后,应用关闭时容器提前销毁导致清理逻辑失效的问题排查与咨询
我们团队维护着一个基于ASP.NET MVC5、OWIN、Web API 2和SignalR的应用,使用Autofac作为依赖注入容器。最近我们调整了OWIN的配置,目的是让OWIN中间件和Web API 2控制器共享同一个生命周期范围——把原来在GlobalConfiguration.Configuration.DependencyResolver设置Autofac解析器的方式,改成了在OWIN里用新的HttpConfiguration()实例来配置。
结果这一改,应用关闭和会话结束时的清理逻辑直接崩了,每次尝试通过全局Autofac容器解析服务时都会抛出ObjectDisposedException:
System.ObjectDisposedException: Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it (or one of its parent scopes) has already been disposed.
我们排查后发现是Autofac的根容器销毁得太早了,导致我们的清理代码根本没法在它销毁前执行(或者说我们不知道怎么让清理代码跑在前面)。目前观察到的应用关闭时的事件顺序是:
- Autofac根容器被销毁(由
AutofacWebApiDependencyResolver触发) - 执行OWIN的
ShuttingDown回调代码 - 触发
MvcApplication.Session_End - 触发
MvcApplication.Application_End
现在我们有几个核心疑问想请教各位:
- 这次配置修改到底哪里出了问题?
- 怎么才能让清理服务的代码在Autofac容器销毁前执行?
- 为什么
AutofacWebApiDependencyResolver会主动销毁根容器? - 为什么在这次“破坏性修改”之前,容器不会在
Session_End前被销毁?
下面是修改前后的代码对比,方便大家定位问题:
之前能正常工作的版本(清理逻辑无异常)
Global.asax.cs
protected void Application_Start() { var container = ConfigureAutofac(); AutofacHelper.Container = container; GlobalHost.DependencyResolver = new Autofac.Integration.SignalR.AutofacDependencyResolver(container); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container); } protected void Session_End(Object sender, EventArgs e) { AutofacHelper.Container.Resolve<ILockService>().ReleaseLocksBySessionId(Session.SessionID); } protected void Application_End() { AutofacHelper.Container.Resolve<ILockService>().ReleaseAllLocks(); }
Startup.cs
public void Configuration(IAppBuilder app) { app.UseAutofacMiddleware(AutofacHelper.Container); ConfigureSession(app); // 初始化会话配置 ConfigureOAuth(app); // 配置SignalR app.MapSignalR(); // 配置认证后逻辑 ConfigurePostAuthentification(app); }
修改后出问题的版本
Global.asax.cs
protected void Application_Start() { var container = ConfigureAutofac(); AutofacHelper.Container = container; GlobalHost.DependencyResolver = new Autofac.Integration.SignalR.AutofacDependencyResolver(container); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); // 注释掉了原来的GlobalConfiguration配置,改成在OWIN里设置Web API解析器 // GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container); } protected void Session_End(Object sender, EventArgs e) { AutofacHelper.Container.Resolve<ILockService>().ReleaseLocksBySessionId(Session.SessionID); } protected void Application_End() { AutofacHelper.Container.Resolve<ILockService>().ReleaseAllLocks(); }
Startup.cs
public void Configuration(IAppBuilder app) { // ***** 尝试在Autofac容器销毁前执行清理代码,但没用,这个回调还是跑在容器销毁之后 ***** var context = new OwinContext(app.Properties); var token = context.Get<CancellationToken>("host.OnAppDisposing"); if (token != CancellationToken.None) { token.Register(() => { Console.WriteLine("Unfortunately this is called after autofac container disposal."); }); } // 配置Autofac与用户上下文 app.UseAutofacMiddleware(AutofacHelper.Container); app.UseAutofacMvc(); var config = new HttpConfiguration(); config.DependencyResolver = new AutofacWebApiDependencyResolver(AutofacHelper.Container); // 注册NodaTime类型 var formatters = config.Formatters; var jsonFormatter = formatters.JsonFormatter; var settings = jsonFormatter.SerializerSettings; settings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb); WebApiConfig.Register(config); app.UseAutofacWebApi(config); ConfigureSession(app); ConfigureOAuth(app); // 配置SignalR app.MapSignalR(); // 配置认证后逻辑 ConfigurePostAuthentication(app); app.UseWebApi(config); }
内容来源于stack exchange
相关产品推荐
相关产品推荐

