Memory leak in Owin.AppBuilderExtensions

后端 未结 4 2168
心在旅途
心在旅途 2020-12-15 05:27

I use OWIN + Microsoft.AspNet.Identity.Owin (v.2.0.0.0) in Web application. I register UserManager/DbContext per web request, as widely recommended:

app.Crea         


        
相关标签:
4条回答
  • 2020-12-15 06:17

    The memory leak in AppBuilderExtensions class has been already fixed in latest version of Microsoft.AspNet.Identity.Owin library (2.2.1).

    I have checked the code by using Reflector and also by putting a breakpoint into Dispose() methods of objects created by AppBuilderExtensions.CreatePerOwinContext().

    0 讨论(0)
  • 2020-12-15 06:20

    I also have his issue, nothing that is registered with CreatePerOwinContext gets disposed. I'm using v2.1.

    Here's a temporary fix which is working well for me as a work around until this lib is fixed. You basically have to manually register each of the types that use register with CreatePerOwnContext in the following class, and then at the end of your Startup procedure you register this custom class:

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

    At the end up your Startup process register this class:

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

    Now everything will get disposed of at the end of the request pipeline properly.

    0 讨论(0)
  • 2020-12-15 06:25

    Usage : app.CreatePerRequest<AuthorizationContext>();

    Extension Method :

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

    To Use Dependency Injection you have to configure owin : app.UseScopePerOwinRequest(_dependencyResolver); - This should be first middleware..

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

    And for above code to work you have to implement IDepedencyResolver with any container.

    • The request comes in and new scope for request get created
    • Within that scope you create other object.
    • Use those objects in other middleware
    • and when the scope is over, it get disposed.
    • any objects within that scope which is not disposed also get disposed off.
    0 讨论(0)
  • 2020-12-15 06:28

    You can put the logic for disposing the instances you create with CreatePeOwinContext() in the same callback you use to create this intances. That is:

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

    Then you only should care about to include a call to DisposeOnPipelineCompleted() within the callback used to instantiate your class. That is:

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

    Also don't forget to include the Dispose() method on your class definition!

    0 讨论(0)
提交回复
热议问题