Mam 2 implementacje tego samego interfejsu i chcę użyć implementation1, jeśli użytkownik jest zalogowany lub implementacja2, jeśli użytkownik nie jest zalogowany. Jak skonfigurować to z windsor zamku?Castle windor Dodawanie warunkowej zależności
Odpowiedz
Jednym ze sposobów rozwiązania tego problemu jest zarejestrowanie usługi za pomocą klucza, a następnie rozwiązanie zgodnie z potrzebą.
public interface ISample
{
int Calculate(int a, int b);
}
class SampleB : ISample
{
public int Calculate(int a, int b)
{
return a + b + 10;
}
}
class SampleA : ISample
{
public int Calculate(int a, int b)
{
return a + b;
}
}
Rejestracja:
container.Register(Component.For<ISample>().ImplementedBy<SampleA>().Named("SampleA").LifeStyle.Transient);
container.Register(Component.For<ISample>().ImplementedBy<SampleB>().Named("SampleB").LifeStyle.Transient);
// Resolve gdy SampleA potrzebne.
var sampleA = container.Resolve<ISample>("SampleA");
// Rozwiązać, gdy potrzebne jest SampleB.
var sampleB = container.Resolve<ISample>("SampleB");
Można dodać handler selector, który byłby w stanie wybrać między implementacje dostępne w zależności od np czy ustawiono Thread.CurrentPrincipal
(lub HttpContext.Current.Request.IsAuthenticated
w ASP.NET/MVC, jeśli dobrze pamiętam).
Selektor obsługi prawdopodobnie wyglądać nieco jak poniżej:
public class MyAuthHandlerSelector : IHandlerSelector
{
public bool HasOpinionAbout(string key, Type service)
{
return service == typeof(ITheServiceICareAbout);
}
public IHandler SelectHandler(string key, Type service, IHandler[] handlers)
{
return IsAuthenticated
? FindHandlerForAuthenticatedUser(handlers)
: FindGuestHandler(handlers);
}
bool IsAuthenticated
{
get { return Thread.CurrentPrincipal != null; }
}
// ....
}
Jedynym minusem jest to, że selektorów procedur obsługi oni nie wyciągnął ze zbiornika - czyli są one dodawane jako przykład do pojemnika przy rejestracji czas, więc nie mają wstrzykniętych zależności, stylu życia itp., ale są sposoby na złagodzenie tego - spójrz na F.T.Windsor, jeśli chcesz zobaczyć, jak można to zrobić.
zastanawiasz się, czy w wersji 3.0 coś się zmieniło - mam na myśli to, czy nadal jest potrzebny zewnętrzny obiekt. – Giedrius
gdzie nazwałbyś 'container.Resolve()'? –
Windsor nie wie, że użytkownik jest zalogowany, chyba że zmienisz/rozszerzysz jego wewnętrzną implementację. Może istnieć klasa Decider pomiędzy, która weźmie pod uwagę "czynnik logowania" i poda pożądaną implementację. –
Windsor * ma * mechanizmy do tego (patrz odpowiedź mookida), nie ma potrzeby zmiany jego wewnętrznej implementacji w ogóle. –