Owin.AppBuilderExtensions中的内存泄漏

我在Web应用程序中使用OWIN + Microsoft.AspNet.Identity.Owin(v.2.0.0.0)。 我按照广泛推荐的方式为每个Web请求注册UserManager / DbContext:

app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext(ApplicationUserManager.Create); 

但都没有处理过。 我瞥了一眼reflection器,看起来像扩展方法中的一个bug:

 public static IAppBuilder CreatePerOwinContext(this IAppBuilder app, Func<IdentityFactoryOptions, IOwinContext, T> createCallback) where T: class, IDisposable { if (app == null) { throw new ArgumentNullException("app"); } if (createCallback == null) { throw new ArgumentNullException("createCallback"); } object[] args = new object[1]; IdentityFactoryOptions options = new IdentityFactoryOptions { DataProtectionProvider = app.GetDataProtectionProvider() }; IdentityFactoryProvider provider = new IdentityFactoryProvider { OnCreate = createCallback }; options.Provider = provider; args[0] = options; app.Use(typeof(IdentityFactoryMiddleware<T, IdentityFactoryOptions>), args); return app; } 

IdentityFactoryProvider有两个回调 – 创建和dispose,但是这里没有注册dispose回调。 我也证实了我对记忆探测器的怀疑。

我没有在codeplex / github上看到Owin(实际上我认为它是开源的),所以我不知道在哪里问我的问题:还有其他人可以确认这是内存泄漏吗? 我不确定,因为谷歌没有说它,我希望它应该在任何地方讨论,如果这是一个错误。

我也有他的问题,没有任何在CreatePerOwinContext注册的东西被处理掉。 我正在使用v2.1。

这是一个临时修复,对我来说很有效,直到修复了这个lib。 您基本上必须在以下类中手动注册使用Register与CreatePerOwnContext的每种类型,然后在启动过程结束时注册此自定义类:

 public sealed class OwinContextDisposal : IDisposable { private readonly List _disposables = new List(); public OwinContextDisposal(IOwinContext owinContext) { if (HttpContext.Current == null) return; //TODO: Add all owin context disposable types here _disposables.Add(owinContext.Get()); _disposables.Add(owinContext.Get()); HttpContext.Current.DisposeOnPipelineCompleted(this); } public void Dispose() { foreach (var disposable in _disposables) { disposable.Dispose(); } } } 

最后,您的启动过程会注册此类:

  app.CreatePerOwinContext( (o, c) => new OwinContextDisposal(c)); 

现在一切都将在请求管道的末尾正确处理掉。

AppBuilderExtensions类中的内存泄漏已在最新版本的Microsoft.AspNet.Identity.Owin库( 2.2.1 )中修复。

我已经使用Reflector检查了代码,并将断点放入AppBuilderExtensions.CreatePerOwinContext()创建的对象的Dispose()方法中。

您可以将使用CreatePeOwinContext()创建的实例的逻辑放在用于创建此内容的同一回调中。 那是:

 public class Startup { public void Configuration(IAppBuilder app) { app.CreatePerOwinContext(ClassIWantOneInstancePerContext.Create); //other code... } } 

那么你应该只关心在用于实例化你的类的回调中包含对DisposeOnPipelineCompleted()的调用。 那是:

 public class ClassIWantOneInstancePerContext { //other code... public static ClassIWantOneInstancePerContext Create() { ClassIWantOneInstancePerContext TheInstance = new ClassIWantOneInstancePerContext(); HttpContext.Current.DisposeOnPipelineCompleted(TheInstance); return TheInstance; } } 

另外,不要忘记在类定义中包含Dispose()方法!

用法: app.CreatePerRequest();

扩展方法:

 public static IAppBuilder CreatePerRequest(this IAppBuilder builder )where T:IDisposable { builder.Use(async (context, next) => { var resolver = context.Get(); using (var instance = (T) resolver.GetService(typeof (T))) { context.Set(instance); if (next != null) { await next(); } } }); return builder; } 

要使用dependency injection,您必须配置app.UseScopePerOwinRequest(_dependencyResolver);app.UseScopePerOwinRequest(_dependencyResolver); – 这应该是第一个中间件..

 public static IAppBuilder UseScopePerOwinRequest(this IAppBuilder builder,IDependencyResolver resolver) { builder.Use(async (context, next) => { using (var instance = resolver.BeginScope()) { context.Set(instance); if (next != null) { await next(); } } }); return builder; } 

要使上述代码工作,您必须使用任何容器实现IDepedencyResolver。

  • 请求进入并创建了新的请求范围
  • 在该范围内,您可以创建其他对象。
  • 在其他中间件中使用这些对象
  • 当范围结束时,它会被处理掉。
  • 该范围内未配置的任何物体也会被处理掉。