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