2

die unter Umsetzung in Burg windsor In Anbetracht 3.4.0:Schloss Windsor UsingFactoryMethod mit LifestyleTransient

public class ExampleInstaller : IWindsorInstaller 
{ 
    public void Install(IWindsorContainer container, IConfigurationStore store) 
    { 
     container.Register(Component.For<FailoverDatabaseConnectionExecutor>() 
     .ImplementedBy<FailoverDatabaseConnectionExecutor>() 
     .LifestyleTransient()); 

     container.Register(Component.For<DatabaseConnectionExecutor>() 
     .ImplementedBy<DatabaseConnectionExecutor>() 
     .LifestyleTransient()); 

     container.Register(Component.For<IDatabaseConnectionExecutor>() 
     UsingFactoryMethod(CreateDatabaseConnectionExecutor) 
     .LifestyleTransient() 
     .IsDefault()); 
    } 

    private static IDatabaseConnectionExecutor CreateDatabaseConnectionExecutor(IKernel kernel) 
    { 
     var configurationRepository = kernel.Resolve<IConfigurationRepository>(); 

     return configurationRepository.GetSetting(ConfigurationSettings.DatabaseFailoverEnabled,() => false) 
      ? (IDatabaseConnectionExecutor)kernel.Resolve<FailoverDatabaseConnectionExecutor>() 
      : kernel.Resolve<DatabaseConnectionExecutor>(); 
    } 
} 

Das Framework die folgende Ausnahme zurückkehrt:

Instanz FailoverDatabaseConnectionExecutor der Komponente Späte IDatabaseConnectionExecutor gebunden ist bereits verfolgt werden. Die Factory Methode, die Instanzen der Komponente zur Verfügung stellt Instanzen wiederverwenden, aber der Lebensstil der Komponente ist Transient, die jedes Mal neue Instanz benötigt. In den meisten Fällen wird empfohlen, die Factory-Methode nicht mit der Wiederverwendung der Instanzen zu behandeln, sondern einen Lebensstil zu wählen, der dies richtig macht. Alternativ, wenn Sie nicht für Windsor wollen die Objekte aus der Fabrik kommen verfolgen ändern Ihre regustration zu ‚.UsingFactoryMethod (yourFactory, managedExternally: true)‘

Dies resultiert in der Abhängigkeitskette versagt zu lösen und ein Nullwert auf der Eigenschaft, die auf unseren Controller injiziert wird.

Wir versuchen, die Auflösung basierend auf dem Konfigurationswert ConfigurationSettings.DatabaseFailoverEnabled zu ändern. Wir möchten, dass dies sowohl auf der Factory als auch auf den zugrunde liegenden aufgelösten Typen vorübergehend geschieht.

Von der Fehler scheint es dies nicht möglich ist, ist unsere Frage wie realisieren wir eine Implementierung Fabrik Stil, während immer noch die FailoverDatabaseConnectionExecutor und DatabaseConnectionExecutor eine vorübergehende Lebenszyklus sowohl die Aufrechterhaltung

EDIT:

Nach Wenn ich etwas Zeit damit verbringe, dies weiter zu untersuchen, scheint es sich um ein Problem zu handeln, das eines der Objekte in meiner Abhängigkeitskette betrifft. Wenn eines der Objekte IDisposable implementiert, tritt dieser Fehler auf, wenn in Verbindung mit UsingFactoryMethod verwandt wird.

Betrachten wir die folgenden (vereinfachtes) Beispiel:

public class ServiceInstaller : IWindsorInstaller 
{ 
    public void Install(IWindsorContainer container, IConfigurationStore store) 
    { 
     container.Register(
      Component.For<ISomeConnectionService>() 
       .ImplementedBy<SomeConnectionService>() 
       .LifestyleTransient() 
       .IsDefault()); 

     container.Register(
      Component.For<FailoverDatabaseConnectionExecutor>() 
      .ImplementedBy<FailoverDatabaseConnectionExecutor>() 
      .LifestyleTransient()); 

     container.Register(Component.For<IDatabaseConnectionExecutor>() 
      .UsingFactoryMethod(CreateDatabaseConnectionExecutor) 
      .LifestyleTransient() 
      .IsDefault()); 
    } 

    private static IDatabaseConnectionExecutor CreateDatabaseConnectionExecutor(IKernel kernel) 
    { 
     return kernel.Resolve<FailoverDatabaseConnectionExecutor>(); 
    } 
} 

public interface IDatabaseConnectionExecutor 
{ 
} 

public class SomeConnectionService : ISomeConnectionService, IDisposable 
{ 
    public SomeConnectionService() 
    { 

    } 

    public void Dispose() 
    { 
    } 
} 

public interface ISomeConnectionService 
{ 
} 

public class FailoverDatabaseConnectionExecutor : IDatabaseConnectionExecutor 
{ 
    private readonly ISomeConnectionService _someConnectionService; 

    public FailoverDatabaseConnectionExecutor(ISomeConnectionService someConnectionService) 
    { 
     _someConnectionService = someConnectionService; 
    } 
} 

IDisposable aus SomeConnectionService Entfernen wird korrekt die Abhängigkeitskette injizieren.

Weiß jemand, warum dies in Burg Windsor der Fall ist?

+0

Bitte versuchen Sie das ConfigurationRepository zu releasen(), bevor Sie von Ihrer Factory-Methode zurückkehren. Wenn Sie Castle verwenden, sollten Sie sich angewöhnen, Release() für alles, was Sie auflösen(), explizit aufzurufen. –

Antwort

0

durch einen Teil der Burg windsor Code Nach der Arbeit scheint es offensichtlich, dass ein Problem irgendwo in Bezug gibt es Objekte zu messen, die für decommission gekennzeichnet sind.More details can be found here

Wir haben dies überwunden, indem wir den IHandlerSelector verwendet haben. Auf diese Weise konnten wir dynamisch eine Abhängigkeit zur Laufzeit basierend auf den Konfigurationseinstellungen auswählen.

public class RepositoriesInstaller : IWindsorInstaller 
{ 
    public void Install(IWindsorContainer container, IConfigurationStore store) 
    { 
     container.Register(Component.For<IDatabaseConnectionExecutor>() 
      .ImplementedBy<FailoverDatabaseConnectionExecutor>() 

      .LifestyleTransient()); 

     container.Register(Component.For<IDatabaseConnectionExecutor>() 
      .ImplementedBy<DatabaseConnectionExecutor>() 
      .LifestyleTransient()); 

     var configuration = container.Resolve<IConfigurationRepository>(); 

     container.Kernel.AddHandlerSelector(new DatabaseExecutorHandlerSelector(configuration)); 

     container.Release(configuration); 
    } 
} 

public class DatabaseExecutorHandlerSelector : IHandlerSelector 
{ 
    private readonly IConfigurationRepository configurationRepository; 

    public DatabaseExecutorHandlerSelector(IConfigurationRepository configurationRepository) 
    { 
     this.configurationRepository = configurationRepository; 
    } 

    public bool HasOpinionAbout(string key, Type service) 
    { 
     return service == typeof(IDatabaseConnectionExecutor); 
    } 

    public IHandler SelectHandler(string key, Type service, IHandler[] handlers) 
    { 
     var failoverEnabled = configurationRepository.GetSetting(ConfigurationSettings.BagDatabaseFailoverEnabled,() => false); 

     var implementationToUse = failoverEnabled ? 
      typeof(FailoverDatabaseConnectionExecutor) : 
      typeof(DatabaseConnectionExecutor); 

     return handlers.First(x => x.ComponentModel.Implementation == implementationToUse); 
    } 
} 
0

Das Problem hier ist, dass. UsingFactoryMethod() eine bereits registrierte Komponente zurückgibt und dann versucht, es erneut zu registrieren.

Sie können versuchen, .Named() zu Ihrer ersten und zweiten Registrierung hinzuzufügen.

container.Register(Component.For<IDatabaseConnectionExecutor>() 
    .ImplementedBy<FailoverDatabaseConnectionExecutor>() 
    .Named('FailoverExecutor') 
    .LifestyleTransient()); 

container.Register(Component.For<IDatabaseConnectionExecutor>() 
    .ImplementedBy<DatabaseConnectionExecutor>() 
    .Named('NormalExecutor') 
    .LifestyleTransient()); 

container.Register(Component.For<IDatabaseConnectionExecutor>() 
    UsingFactoryMethod(CreateDatabaseConnectionExecutor) 
    .LifestyleTransient() 
    .IsDefault()); 

In Ihrer Factory-Methode lösen Sie dann die Komponenten mit dem Namen.

return configurationRepository.GetSetting(ConfigurationSettings.DatabaseFailoverEnabled,() => false) 
     ? kernel.Resolve<IDatabaseConnectionExecutor>("FailoverExecutor") 
     : kernel.Resolve<IDatabaseConnectionExecutor>("NormalExecutor"); 
Verwandte Themen