2017-05-17 10 views
1

Ich verwende Simple Injector. Ich habe einen Hintergrundprozessor, der DI von Anfang an verwendet. Es werden Jobs zum Ausführen abgeholt und ausgeführt. Jeder Job muss jedoch in seinem eigenen Bereich ausgeführt werden, damit ich einige kontextabhängige Abhängigkeiten überschreiben kann. Der Job muss beispielsweise in einem bestimmten Sicherheitskontext (demjenigen, aus dem er erstellt wurde) ausgeführt werden. Daher muss ich einen neuen Bereich starten und die ISecurityContext Injektion überschreiben, damit der Job ordnungsgemäß gesichert wird.Ordnungsgemäße Methode zum Überschreiben von Abhängigkeiten innerhalb eines Bereichs

Um dies zu erreichen, erstellte ich einen neuen Container (mit der richtigen) und starten einen Bereich, dann den Job ausgeführt, aber ich bin mir nicht sicher, ob dies eine geeignete Sache zu tun ist.

RunJob

private readonly Func<ISecurityContext, Container> _containerFactory; 

internal async Task RunJob(BackgroundJob job) { 
    var parameters = job.GetParameters(); 
    var securityContext = parameters.SecurityContext; 

    using (var container = _containerFactory(securityContext)) 
    using (AsyncScopedLifestyle.BeginScope(container)) { 
     // Run the job within this scope. 
    } 
} 

DI Bits

container.RegisterSingleton<Func<ISecurityContext, Container>>(() => securityContext => { 
    var c = new Container(); 

    RegisterDependencies(c); 

    c.Options.AllowOverridingRegistrations = true; 
    c.Register<ISecurityContext>(() => securityContext, Lifestyle.Scoped); 

    return c; 
}); 

Es fühlt sich nicht richtig für mich, aber ich bin mir nicht sicher, was die richtige Lösung ist.

Antwort

3

Die einfache Injector Dokumentation warns über das, was Sie mit der Feststellung machen:

Warnung: Sie eine unendliche Anzahl von Container-Instanzen nicht schaffen (wie eine Instanz pro Anfrage). Dadurch wird die Leistung Ihrer Anwendung beeinträchtigt. Die Bibliothek ist für die Verwendung einer sehr begrenzten Anzahl von Container-Instanzen optimiert. Das Erstellen und Initialisieren von Container-Instanzen hat einen großen Aufwand, aber die Auflösung aus dem Container ist nach der Initialisierung extrem schnell.

In der Regel sollten Sie nur eineContainer Instanz pro Anwendung erstellen. Dies gilt nicht nur für die Performance, sondern die Schaffung solcher "Kindercontainer" ist im Allgemeinen mit Macken und Fehlern behaftet. Wie kann beispielsweise sichergestellt werden, dass Registrierungen Singletons in der gesamten Anwendung sind?

Also missbrauchen Sie den Container nicht für Ihren Laufzeitstatus, sondern speichern Sie ihn woanders. Sie können eine Scope Instanz als Wörterbuch für den Gültigkeitsbereich verwenden, aber es ist so einfach, einen einfachen Wrapper für zu erstellen, der als Scoped Instanz registriert ist und direkt nach der Erstellung des Bereichs initialisiert wird, wie im folgenden Beispiel gezeigt.

// Can be part of your Composition Root 
internal sealed class SecurityContextWrapper : ISecurityContext 
{ 
    // One of the rare cases that Property Injection makes sense. 
    public ISecurityContext WrappedSecurityContext { get; set; } 

    // Implement ISecurityContext methods here that delegate to WrappedSecurityContext. 
} 


// Composition Root. Only have 1 container for the complete application 
c = new Container(); 

RegisterDependencies(c); 

c.Register<SecurityContextWrapper>(Lifestyle.Scoped); 
c.Register<ISecurityContext, SecurityContextWrapper>(Lifestyle.Scoped); 


// Job logic 
private readonly Container _container; 

internal async Task RunJob(BackgroundJob job) { 
    var parameters = job.GetParameters(); 
    var securityContext = parameters.SecurityContext; 

    using (AsyncScopedLifestyle.BeginScope(_container)) { 
     // Resolve the wapper inside the scope 
     var wrapper = _container.GetInstance<SecurityContextWrapper>(); 
     // Set it's wrapped value. 
     wrapper.WrappedSecurityContext = securityContext; 

     // Run the job within this scope. 
    } 
} 

Alternativ, wenn Sie Scope als Zustand verwenden, können Sie eine Scope Instanz als Konstruktorargument von SecurityContextWrapper injizieren. Das entfernt die Notwendigkeit, Property Injection zu verwenden, aber macht Ihre SecurityContextWrapper abhängig von Simple Injector:

+0

Ausgezeichnet, vielen Dank. Dies ist definitiv eine große Verbesserung. –

Verwandte Themen