0

Während der Bootstrapping ConfigureServices() meiner Anwendung registriere ich hauptsächlich Transienten und Bereichstypen mit der Dependency-Injection-Framework, das .Net Core. Allerdings habe ich einen Typ, der als Singleton registriert ist, ist meine InProcessBus (ich benutze eine CQRS-Architektur).IServiceProvider.GetSingleton Auflösung Null in Asp.Net Core DI

services.AddSingleton<InProcessBus>(new InProcessBus()); 
...   
services.AddSingleton<ICommandSender>(y => y.GetService<InProcessBus>()); 
services.AddSingleton<IEventPublisher>(y => y.GetService<InProcessBus>()); 

Wie man sehen kann ich Implementierung Werksfunktionen für die tatsächlichen Typen verwenden, die in der Steuerung der APIs verwendet werden. Die wirklich bizarre Sache ist, wenn der Controller lädt und die Laufzeit versucht,.zu konstruieren injizieren es schlägt fehl und meldet einen Fehler.

Wenn ich die serviceCollection inspizieren kann ich sehen, dass die implementationFactory richtig gegen die Art unter dem ImplementationInstance Eigentum registriert ist.

Die tiefere und direkte Auflösung des Typs am Ende der Startup Klasse ConfigureServices() Methode bestätigt, dass der Container null löst.

Warum wird eine ImplementationFactory-Methode für einen eindeutig im Container vorhandenen Singleton zur Laufzeit nicht aufgelöst?

+0

Das ist seltsam. Sie sollten jedoch vermeiden, 'y.GetService ()' zu verwenden und 'y.GetRequiredService ()' zu verwenden, das eine Ausnahme auslöst, wenn sie nicht aufgelöst werden kann, anstatt null zurückzugeben. Obwohl das wahrscheinlich Ihr Problem nicht lösen wird. Gibt es mehr dazu? Sie können es auch nicht in 'ConfigureServices' auflösen. Zu diesem Zeitpunkt ist der Container noch nicht gebaut. Earlierst Punkt, den Sie Dienste auflösen können, ist in 'Configure' Methode (wenn Sie die Standard-Startup.cs verwenden, die mit den Vorlagen geliefert wird) – Tseng

+0

Sind Sie sicher, dass Sie den integrierten Container verwenden möchten? CQRS-Architekturstile sind wirklich leistungsfähig, da sie es sehr einfach machen, übergreifende Probleme mit Dekoratoren zu lösen. Es ist nicht möglich, generische Dekoratoren mit dem integrierten Container zu verwenden. – Steven

+0

@Tseng, danke für den Tipp GetRequiredService, eine explizite Ausnahme ist besser als Null. Gewöhnlich wäre nicht in der Lage, ja zu lösen, aber ich BuildServiceProvider() verwendet, um meinen eigenen Anbieter mit inline zu testen, wenn ich das Problem hatte ... –

Antwort

3

Ich fand was falsch war und dachte, ich würde es hier posten, da es eine wichtige Lektion darin gibt.

Die kurze Antwort:

Aufschieben serviceCollection.BuildServiceProvider(), nachdem Sie alle Ihre Singleton Instanzen registriert haben sonst wird es nicht in der Lage sein, sie zu lösen.

Die lange Antwort:

Das Problem eigentlich nichts hatte mit dem asp Kern DI-Container (gut sorta) zu tun. Das Problem ist mit dem Timing von, wenn ich BuildServiceProvider auf der serviceCollection Instanz anrufe, um mir eine IServiceProvider zur Verfügung zu stellen.

In meiner Implementierung habe ich ein ServiceLocator Muster implementiert, das das DI-Framework, das mit Core geliefert wird, umschließt, sodass ich keine zusätzliche Abhängigkeit in meinen anderen Architekturebenen einfüge. Wenn ich meine IServiceContainer basierte Locator konstruieren sofort behebe ich die ServiceProvider

public ServiceLocator(
     IServiceCollection serviceCollection) 
    { 
     _serviceCollection = serviceCollection; 
     _serviceProvider = _serviceCollection.BuildServiceProvider(); 
    } 

Und das ist, wo das Problem eingeschlichen. Die Zeit, dass ServiceProvider offensichtlich keine Rolle spielt für Transients und Scoped Instanzen erstellt bekommen. Aber für Singletons, die eine verwaltete Lebensdauer haben, tut es. Sie müssen die Erstellung Ihres ServiceProviders nach allen Anmeldungen verschieben.

Aus meiner Frage wurde die ServiceLocator vor den Ausschnitten erstellt, was bedeutet, dass die Singleton-Instanz ServiceProvider nicht zugänglich gewesen wäre, wenn die implementationFactory-Funktion ausgeführt wird.

Durch die Verschiebung der Erstellung des ServiceProvider zu dem ersten Mal, löst meine Anwendung einen meiner benutzerdefinierten Typen während der Laufzeit das Problem gelöst.

+0

Sie haben wahrscheinlich andere Probleme mit diesem Ansatz (ignorieren die Tatsache, dass Service Locator Anti-Pattern ist und schlägt den gesamten Zweck von DI/IoC): Sie haben jetzt zwei Container in Ihrem System, eine, die ASP.NET Core zuvor erstellt Aufrufen von 'Configure' und eines, das Sie für Ihren Anti-Pattern-Locator erstellt haben. Dies ist ein Problem mit Dienstbereichen (DbContext), da Ihre Dienste mit ASP.NET Core IoC und die mit Ihrem Dienst-Locator unterschiedliche Instanzen aufrufen SaveChanges() 'zum Beispiel wird nicht die Änderungen von Ihrem anderen Kontext sichern und Sie verlieren die Einheit der Arbeit Vorteil – Tseng

+0

Auch könnten Sie" _pattern, die das DI-Framework, das mit Kern geliefert wird, so dass ich keine zusätzliche Abhängigkeit einführen in meinen anderen architektonischen Schichten? Sie brauchen keine anderen Abhängigkeiten in Ihren anderen Schichten zu 'Microsoft.Extensions.DependencyInjection'. Sie benötigen es nur in der Webanwendung (in der Sie Ihr Objektdiagramm im Kompositionswurzel erstellen). Ihre Herangehensweise scheint aus architektonischer Sicht sehr falsch zu sein, und sie erzeugt eine harte Abhängigkeit und wird schwierig/unmöglich zum Komponententest – Tseng

Verwandte Themen