2013-08-02 17 views
19

Podczas rejestrowania komponentów w Castle Windsor, w jaki sposób wiążemy określoną implementację interfejsu z komponentem, który jest zależny od tego interfejsu. Z góry wiem, która implementacja musi być użyta przez komponent.Castle Windsor - wielokrotna implementacja interfejsu

Na przykład stworzyłem przykładową aplikację konsolową opartą na kodzie z kilku blogów i samouczków.

Poniżej znajduje się kod.

public interface IReport 
{ 
    void LogReport(); 
} 

public interface ILogger 
{ 
    string Log(); 
} 

public class FileLogger : ILogger 
{ 
    public string Log() 
    { 
     return "Logged data to a file"; 
    } 
} 

public class DatabaseLogger : ILogger 
{ 
    public string Log() 
    { 
     return "Logged data to a database"; 
    } 
} 

public class McAfeeService : IReport 
{ 
    private readonly ILogger _logger; 

    public McAfeeService(ILogger logger) 
    { 
     this._logger = logger; 
    } 

    public void LogReport() 
    { 
     string getLogResult = this._logger.Log(); 

     Console.WriteLine("McAfee Scan has " + getLogResult); 
    }   
} 

public class NortonService : IReport 
{ 
    private readonly ILogger _logger; 

    public NortonService(ILogger logger) 
    { 
     this._logger = logger; 
    } 

    public void LogReport() 
    { 
     string getLogResult = this._logger.Log(); 

     Console.WriteLine("Norton Scan has " + getLogResult); 
    } 
} 

class Program 
{ 
    private static IWindsorContainer container; 

    static void Main(string[] args) 
    { 
     // Register components 
     container = new WindsorContainer(); 

     container.Register(Component.For<IReport>().ImplementedBy<NortonService>()); 
     container.Register(Component.For<ILogger>().ImplementedBy<FileLogger>()); 

     IReport service = container.Resolve<IReport>(); 
     service.LogReport(); 

     Console.ReadLine(); 
    } 
} 

Chciałbym, aby NortonService zawsze używał Filelogger i McAfeeService do używania Loggeru bazy danych.

W powyższym programie nie można powiązać NortonService z FileLogger.

Jak to zrobić?

Odpowiedz

2

Moja odpowiedź może nie najlepszy, można użyć metody nazewnictwa w celu rozwiązania wielu realizacji:

container.Register(Component.For(typeof(ILogger)) 
      .ImplementedBy(typeof(FileLogger)) 
      .Named("FileLoggerIoC") 
      .LifestylePerWebRequest() , 
      Component.For(typeof(ILogger)) 
      .ImplementedBy(typeof(DatabaseLogger)) 
      .Named("DatabaseLoggerIoC") 
      .LifestylePerWebRequest()); 

w twojej funkcji połączeń, trzeba rozwiązać go po imieniu: -

var fileLog = container.Resolve("FileLoggerIoC", typeof(ILogger)); 
var DbLog = container.Resolve("DatabaseLoggerIoC", typeof(ILogger)); 

Metoda kopalni może nie jest najlepsza, ponieważ ludzie nie lubią lokalizatora usług, aby uzyskać komponenty, możesz użyć tego jako tymczasowego rozwiązania.

20

Powyższe odpowiedzi doprowadzić mnie do inline zależności i funkcji service override

Oto kod rejestracyjny:

container.Register(Component.For<IReport>().ImplementedBy<NortonService>().Named("nortonService")); 

container.Register(Component.For<ILogger>().ImplementedBy<FileLogger>()); 
container.Register(Component.For<ILogger>().ImplementedBy<DatabaseLogger>()); 

container.Register(
    Component.For<IReport>().ImplementedBy<McAfeeService>().Named("mcafeeService") 
     .DependsOn(Dependency.OnComponent<ILogger, DatabaseLogger>()) 
); 

IReport mcafeescan = container.Resolve<IReport>("mcafeeService"); 
mcafeescan.LogReport(); 

IReport nortonscan = container.Resolve<IReport>("nortonService"); 
nortonscan.LogReport(); 

wyjściowa:

McAfee Scan has Logged data to a database 
Norton Scan has Logged data to a file 
9

miałem problem bardzo podobnie jak ten, dwie implementacje jednego interfejsu i dwie implementacje innego interfejsu. Chciałem wymusić użycie konkretnych implementacji tych interfejsów.

Moja klasa struktura wygląda tak -

enter image description here

Spojrzałem na konwencji nazewnictwa, ale tak naprawdę nie podoba. Zamiast tego stosuje się następującą -

public void Install(IWindsorContainer container, IConfigurationStore store) 
    { 
    container.Register(
     Component.For<IMessageLoader>().ImplementedBy<MessageLoaderDatabase>() 
     ,Component.For<IMessageLoader>().ImplementedBy<MessageLoaderFile>() 

     ,Component.For<IMessageOfTheDayService>().ImplementedBy<MessageOfTheDayServiceDatabase>() 
      .DependsOn(Dependency.OnComponent<IMessageLoader, MessageLoaderDatabase>()) 

     ,Component.For<IMessageOfTheDayService>().ImplementedBy<MessageOfTheDayServiceFile>() 
      .DependsOn(Dependency.OnComponent<IMessageLoader, MessageLoaderFile>()) 

     ,Component.For<MessageOfTheDayController>().LifestyleTransient() 
      .DependsOn(Dependency.OnComponent<IMessageOfTheDayService, MessageOfTheDayServiceFile>()) 
    ); 

Pełna informacja na temat tego podejścia jest here. W kodzie źródłowym podanym w tym poście pokazuję dwa inne sposoby osiągnięcia tego samego rezultatu.

2

Jeśli chcesz to zrobić w czasie wykonywania, można to osiągnąć za pomocą IHandlerSelector. Napisz klasę, która implementuje IHandlerSelector. Dostarcza metodę SelectHandler, która pozwala zdefiniować warunek dla wiązania warunkowo w środowisku wykonawczym. Handler w tym przypadku jest elementem Windsor, który uczestniczy w budowie instancji. Więcej szczegółowych informacji można znaleźć na stronie here.

Powiązane problemy