2014-06-24 6 views
20

Ich verwende OWIN + Microsoft.AspNet.Identity.Owin (v.2.0.0.0) in Webanwendung. Ich registriere UserManager/DbContext pro Web-Anfrage, wie es weithin empfohlen wird:Speicherverlust in Owin.AppBuilderExtensions

aber keiner ist jemals entsorgt. Ich nahm einen Blick Blick in Reflektor und es scheint, wie ein Fehler in Erweiterungsmethode:

public static IAppBuilder CreatePerOwinContext<T>(this IAppBuilder app, Func<IdentityFactoryOptions<T>, 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<T> options = new IdentityFactoryOptions<T> { 
     DataProtectionProvider = app.GetDataProtectionProvider() 
    }; 
    IdentityFactoryProvider<T> provider = new IdentityFactoryProvider<T> { 
     OnCreate = createCallback 
    }; 
    options.Provider = provider; 
    args[0] = options; 
    app.Use(typeof(IdentityFactoryMiddleware<T, IdentityFactoryOptions<T>>), args); 
    return app; 
} 

IdentityFactoryProvider hat zwei Rückrufe - erstellen und entsorgen, sondern entsorgen Rückruf hier nicht registriert ist. Ich habe auch meinen Verdacht mit Memory Profiler bestätigt.

Ich sehe Owin nicht auf Codeplex/Github (eigentlich dachte ich, es ist Open Source), also weiß ich nicht, wo ich meine Frage stellen soll: Könnte jemand anderes bestätigen, dass dies ein Speicherleck ist? Ich bin nicht so sicher, weil Google nichts darüber sagt, ich erwarte, dass es überall diskutiert werden sollte, wenn das ein Fehler ist.

+1

Ich habe mir die Freiheit genommen, dies an das Microsoft-Team weiterzuleiten, das diesen Code verarbeitet. –

+0

Es wäre nett, ihre Antwort zu hören, wenn überhaupt. –

+0

Zuletzt hörte ich, da wurde das Problem untersucht. Das Hauptproblem ist, dass der Identity-Code nicht Open Source ist und es schwierig ist, eine Pull-Anfrage zu erstellen, um ihn zu reparieren. Im Moment gibt es einen Platzhalter im Codeplex, aber ... noch nichts. Es könnte ein Hinweis darauf sein, dass es sich irgendwann um Open Source handelt. –

Antwort

6

Ich habe auch sein Problem, nichts, das mit CreatePerOwinContext registriert ist, wird entsorgt. Ich benutze v2.1.

Hier ist eine temporäre Korrektur, die gut für mich als eine Arbeit funktioniert, bis diese Lib behoben ist. Sie haben grundsätzlich manuell jede der verschiedenen Arten registrieren, die in der folgenden Klasse mit CreatePerOwnContext registrieren verwenden, und dann am Ende des Startprozedur Sie diese benutzerdefinierte Klasse registrieren:

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(); 
     } 
    } 
} 

Am Ende Ihres Startup-Prozess Register up Diese Klasse:

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

Jetzt wird alles am Ende der Request-Pipeline ordnungsgemäß entsorgt.

1

Sie können die Logik zum Entsorgen der von Ihnen erstellten Instanzen mit CreatePeOwinContext() im selben Callback verwenden, den Sie zum Erstellen dieser Intanzen verwenden. Das heißt:

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

     //other code... 
    } 
} 

Nur dann sollten Sie kümmern sich um einen Anruf zu DisposeOnPipelineCompleted() innerhalb der Callback schließen verwendet, um Ihre Klasse zu instanziieren. Das heißt:

public class ClassIWantOneInstancePerContext 
{ 
    //other code... 

    public static ClassIWantOneInstancePerContext Create() 
    { 
     ClassIWantOneInstancePerContext TheInstance = new ClassIWantOneInstancePerContext(); 
     HttpContext.Current.DisposeOnPipelineCompleted(TheInstance); 

     return TheInstance; 
    } 
} 

Vergessen Sie auch nicht die Dispose() Methode auf Ihrer Klassendefinition enthalten!

+0

Das mag wie ein merkwürdiger Grund aussehen, aber ich möchte innerhalb der OWIN-Abstraktion bleiben und nicht auf System.Web verweisen ... –

+0

Dies führt eine Abhängigkeit von System.Web ein, aber es funktioniert definitiv! – ilikeprogramming

0

Verbrauch: app.CreatePerRequest<AuthorizationContext>();

Erweiterungsmethode:

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; 
     } 

Verwenden Injection Dependency Sie haben owin zu konfigurieren: app.UseScopePerOwinRequest(_dependencyResolver); - Diese erste Middleware sein sollte ..

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; 
     } 

Und oben Code zu arbeiten, müssen Sie IDepecendencyResolver mit einem Container implementieren.

  • Die Anfrage kommt und neue Möglichkeiten für die Anforderung
  • Sie erstellen ein anderes Objekt innerhalb dieses Bereichs erstellt bekommen.
  • Verwenden Sie diese Objekte in anderen Middleware
  • und wenn das Oszilloskop vorbei ist, wird es entsorgt.
  • Alle Objekte in diesem Bereich, die nicht entsorgt werden, werden ebenfalls entsorgt.
5

in AppBuilderExtensions Klasse Der Speicherverlust wurde in neuester Version von Microsoft.AspNet.Identity.Owin Bibliothek (2.2.1) bereits festgelegt.

Ich habe den Code überprüft, indem Sie Reflektor und auch einen Haltepunkt in Dispose() Methoden von Objekten erstellt von AppBuilderExtensions.CreatePerOwinContext().