2017-06-12 1 views
1

Wir haben eine große monolithische Legacy-Anwendung mit rund 45 Projekten mit verschiedenen Composition Roots (Konsole, Web, API-Apps). Die meisten Komponenten werden in den Kompositionswurzeln der Apps und vielen WindsorInstallern registriert. Wir möchten die Komponentenregistrierung aus den Kompositions-Roots und in WindsorInstaller für jedes Projekt in der Lösung entfernen, sodass wir die Kompositionswurzeln nicht mehr ändern müssen, wenn wir ein neues Projekt hinzufügen. Jedes Projekt sollte für seine eigene Komponentenregistrierung verantwortlich sein. Wir möchten diese Änderung schrittweise in unsere Codebasis umwandeln, weil ich versucht habe, Castle Windsor alle unsere Assemblys scannen zu lassen und alle unsere Installateure laufen zu lassen, aber das verursachte eine Unzahl von Problemen, die im Laufe der Zeit untersucht werden müssen.Castle Windsor führt nur bestimmte Arten von Installern über viele Projekte aus

Mit all dem gesagt, wir suchen nach einer Möglichkeit, nur bestimmte Installateure zu führen, so können wir eine Reparatur der gebrochenen im Laufe der Zeit gehen, aber alle neuen werden automatisch verwendet werden. Unten ist der Ansatz, auf den ich hinwollte, aber ich kann nicht herausfinden oder nicht einmal wissen, ob es möglich ist.

Alle Kompositionswurzeln haben so etwas, so dass alle Installer immer ausgeführt werden.

Allerdings möchte ich diesen Installationscode nur Installateure des Typs IAutoInstaller ausführen. Auf diese Weise könnte ich zurückgehen und meine Legacy-Installer reparieren, indem ich einfach die Schnittstelle zu IAutoInstaller ändere und dann nie die Composition-Roots modifizieren müsste.

public interface IAutoInstaller : IWindsorInstaller 
{ 

} 

public class ScheduledPaymentInstaller : IAutoInstaller 
{ 

    public void Install(IWindsorContainer container, IConfigurationStore store) 
    { 
     container.Register(Classes.FromAssemblyNamed("DryFly.ScheduledPayments") 
      .Pick() 
      .WithServiceDefaultInterfaces().LifestylePerWebRequest()); 

    } 
} 

Zusammengefasst, was ich bin, ist nach einer Art und Weise Auto auf bestimmte Installateure aus der Zusammensetzung root ausführen, so dass, wenn ich neue Projekte hinzufügen, ich weiß nicht, dass Code ändern müssen. Ich würde nur ein neues Installationsprogramm zu dem neuen Projekt hinzufügen müssen. Gibt es einen anderen Ansatz, um dieses Problem zu lösen, oder kann dies über Castle Windsor geschehen?

Antwort

0

Es ist möglich, aber nicht recht:

var container = new WindsorContainer(); 
var installers = AppDomain.CurrentDomain 
     .GetAssemblies() // Load all assemblies in the current application domain 
     .SelectMany(s => s.GetTypes()) // project all types contained in all assemblies into a single collection 
     .Where(type => typeof(IAutoInstaller).IsAssignableFrom(type) && type.IsClass) // find all types that implement IAutoInstaller and are classes (this filters out the interface itself) 
     .Select(Activator.CreateInstance) // project all types into instances - this relies on all of them containing a parameterless constructor 
     .Cast<IAutoInstaller>(); // project the Ienumerable<object> into an Ienumerable<IAutoInstaller> 

foreach (var installer in installers) 
{ 
    installer.Install(container, container.Kernel.ConfigurationStore); 
} 

Es gibt hier eine massive Einschränkung, die, dass Ihre Installateure ist einen parameterlosen Konstruktor für diese zu arbeiten haben. Wenn das aus irgendeinem Grund nicht der Fall ist, wird Ihr Problem viel schwieriger allgemein zu lösen.

Leider erzwingt die Schnittstelle IWindsorInstaller nur eine Methode, die den Container selbst erwartet, und eine Implementierung von IConfigurationStore. Selbst wenn Sie keinen Konfigurationsspeicher verwenden, müssen Sie ihn dennoch bereitstellen. Zum Glück, wenn Sie einen WindsorContainer mit dem Standardkonstruktor instanziieren, verdrahtet es einen Standardkernel mit einer DefaultConfigurationStore Implementierung. Dadurch können Sie den Code einfach übergeben.

Wenn Sie jedoch einen benutzerdefinierten Konfigurationsspeicher verwenden (z. B. wenn Sie einen XML-Konfigurationsinterpreter verwenden) und dieser Konfigurationsspeicher einem anderen Container oder einem übergeordneten oder untergeordneten Element gehört Container, der sich auf Ihren aktuellen Container bezieht und Sie Zugriff auf die Werte dieses bestimmten Speichers in Ihrem bestimmten Installationsprogramm benötigen, müssen Sie diesen bestimmten Geschäftsverweis an das Installationsprogramm übergeben.

Wie Sie aus der Liste der Vorbehalte um den Laden sehen können, sind Sie wahrscheinlich sicher, nur die Kernel-Standardeinstellung oder sogar neu eine DefaultConfigurationStore übergeben.

+0

Ich gehe davon aus, dass dieser Code aus dem Kompositionsstamm ausgeführt wird, richtig? Wenn ja, wie bekomme ich eine Instanz des Geschäfts (IConfigurationStore)? – csalzsieder

+0

Korrekt. Ich habe meine Antwort auch auf zwei Arten aktualisiert. Ich habe ausgearbeitet, was der Laden eigentlich ist, und nach Ihrem Kommentar gehe ich davon aus, dass Sie keinen wirklich brauchen. In diesem Fall sollte der von mir angegebene Code ausreichen.Zweitens hatte ich einen Derp-Moment und gab Ihnen einen Ausschnitt, der alle Ihre Installer zweimal durchlaufen würde, einmal für den 'ToList()' Aufruf und einmal für den 'Foreach()'. Wenn Ihre Liste der Installateure angenehm klein ist, würde das keinen großen Unterschied machen, aber ich habe es trotzdem auf eine normale foreach zurückgestellt. –

+0

Ich habe festgestellt, dass die Verwendung der aktuellen App-Domäne nicht alle Assemblys enthält, da sie bei der Auflösung der Referenz geladen werden. Ich werde später nachschauen, wie man stattdessen alles aus dem Ordner "bin" lädt. –

Verwandte Themen