2

캐슬 윈저 아래 구현 3.4.0을 고려하여 다음성 윈저 UsingFactoryMethod는 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>(); 
    } 
} 

다음 예외 복귀 된 워크는 :

컴포넌트의

인스턴스 FailoverDatabaseConnectionExecutor 늦은 IDatabaseConnectionExecutor 결합 는 이미 추적 중입니다. 구성 요소의 공장 방법을 제공하는 인스턴스 구성 요소의 라이프 스타일을 인스턴스를 재사용하지만 된다마다 새로운 인스턴스를 필요로하는 과도이다. 대부분의 경우 팩토리 메서드 은 인스턴스 재사용을 처리하지 말고 적절하게 수행하는 라이프 스타일 을 선택하는 것이 좋습니다. 당신이 추적 에 대한 윈저을하지 않으려면 다른 방법으로, 공장에서 나오는 객체로 regustration 변경 '.UsingFactoryMethod (yourFactory, managedExternally을 : 를 참)'

를이 해결하지 못하는 종속성 체인 결과 우리 컨트롤러의 속성 주입에 대한 null 값.

은 우리가 달성하려고하는 것은 구성 값 ConfigurationSettings.DatabaseFailoverEnabled에 따라 해상도의 스위치입니다. 우리는 이것이 공장과 기본 해결 된 유형 모두에서 일시적으로 발생하기를 원합니다. 이 불가능 보일 것 오류에서

, 우리의 문제는 우리가 공장 스타일의 구현을 실현 어떻게입니다 여전히 FailoverDatabaseConnectionExecutorDatabaseConnectionExecutor

EDIT 모두에 과도 라이프 사이클을 유지하면서 :

후를 이 문제를 조사하면서 시간을 보내면서 내 의존성 체인의 객체 중 하나와 관련된 문제가있는 것처럼 보입니다. 개체 중 하나가 IDisposable을 구현하면 UsingFactoryMethod와 함께 사용하면이 오류가 발생합니다. 올바르게 의존성 체인을 주입한다 SomeConnectionService는 IDisposable로부터 분리

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

:

는 아래 (단순화 된) 예를 고려한다.

성 윈저에있는 이유를 아는 사람이 있습니까?

+0

팩토리 메소드를 반환하기 전에 configurationRepository를 Release()하십시오. Castle을 사용할 때 Resolve()의 모든 것에 대해 Release()를 명시 적으로 호출하는 습관을 갖춰야합니다. –

답변

0

성 윈저 코드의 일부를 통해 작업 후에는 문제가 서비스 해제를 위해 표시된 객체 추적에 관해서 곳이 있음을 알 것 같다.More details can be found here

IHandlerSelector를 사용하도록 전환하여이를 극복했습니다. 이를 통해 구성 설정에 따라 런타임에 종속성을 동적으로 선택할 수있었습니다.

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

여기서 문제는 .UsingFactoryMethod()가 이미 등록 된 구성 요소를 반환 한 다음 다시 등록을 시도하는 것입니다.

당신은 당신의 제 1 및 제 2 등록에 .Named()를 추가 할 수 있습니다.

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

팩토리 메서드에서 이름을 사용하여 구성 요소를 확인합니다.

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