2011-12-05 10 views
6

Mam moduł Autofac który ma następujący (okrojone) logikę w ręcznym obciążenie:Zatrzymaj Autofac moduł Załatwienie już zarejestrowane komponenty

protected override void Load(ContainerBuilder builder) 
    { 
     foreach (var componentType in allTypesInAllAvailableAssemblies) // Set elsewhere 
     { 
      var handlerInterfaces = componentType.GetInterfaces().Where(i => i.IsClosedTypeOf(typeof(IMessageHandler<>))); 
      if (handlerInterfaces.Any()) 
       builder.RegisterType(componentType).As(handlerInterfaces); 
     } 
    } 

Ten szuka jakiejkolwiek klasy, która deklaruje się do obsługi wiadomości i rejestruje go przeciwko wszystkim interfejsom IMessageHandler, które implementuje.

Co chcę zrobić, to nie zarejestrować komponentu, jeśli jest już zarejestrowany. Jako bonus, byłoby idealne, gdybym mógł zaktualizować istniejącą rejestrację, aby rozwiązać problemy z interfejsem komunikatora, jeśli jeszcze nie jest.

Dla argumentu można przyjąć, że ten kod będzie działał po wszystkie inne typy zostały zarejestrowane (w tym ewentualnych kandydatów obsługi komunikatów)

Użyłem AttachToComponentRegistration nadpisanie manipulacji rejestracji w przeszłości, ale nie wygląda na użyteczny w tym scenariuszu.

Czy jest to możliwe, czy powinienem ponownie przemyśleć mój projekt i wymusić wtyczki, aby jawnie zadeklarować ich obsługę?

+0

Czy próbowałeś użyć klasy AnyConcreteTypeNotAlreadyRegisteredSource?Zobacz: http://stackoverflow.com/questions/3413660/ –

Odpowiedz

7
builder.RegisterType(componentType) 
    .As(handlerInterfaces) 
    .PreserveExistingDefaults(); 

Działa, chyba że zaczniesz rozwiązywać listę programów obsługi.

+0

Niestety potrzebuję list procedur obsługi. Skończyło się na zmianie wywoływanej rejestracji w celu wyszukania wszystkich interfejsów programu obsługi, gdy typ jest jawnie zarejestrowany, zamiast wykonywania innego przeciągnięcia wszystkich typów. Pozdrowienia za pomoc - zaakceptowałem to, ponieważ odpowiada na pytanie w formie wysłanej. – JRoughan

1

Niestety nie ma eleganckiego sposobu robienia tego, co chcesz. Kontener Autofac i jego konstruktor to "czarne skrzynki", które nie pozwalają ci dobrze przyjrzeć się temu, co już masz.

Nie ma nic złego w dwukrotnym zarejestrowaniu komponentu, CHYBA, że twoje rejestracje są zależne od zamówienia (ZŁE, ZŁE, ZŁE). Rejestracja po raz drugi spowoduje po prostu zastąpienie starej rejestracji nowym.

Poważnie kwestionuję ten kod, ponieważ zależy on całkowicie od zainicjowania allTypesInAllAvailableAssemblies. Jeśli naprawdę jest to każdy typ w twoim systemie, to jest to bzdura, co się rozwiąże, jak np. IDisposable. Jeśli masz kilka różnych implementacji, powiedzmy, IConfiguratora, będziesz mieć ograniczoną kontrolę nad tym, który z nich zostanie zarejestrowany, niezależnie od tego, czy sprawdzasz, co już zostało zarejestrowane, czy tylko pozwalasz na nadpisanie rejestracji; zależy to całkowicie od tego, która klasa kończy się na pierwszym (lub ostatnim) liście.

Jedyne co mogłem myśleć zrobić, to użyć trochę Linq aby upewnić się, że lista typów rejestrujesz jest wyjątkowy:

protected override void Load(ContainerBuilder builder) 
{ 
    foreach (var componentType in allTypesInAllAvailableAssemblies.OfType<Type>().Distinct()) // Set elsewhere 
    { 
     var handlerInterfaces = componentType.GetInterfaces().Where(i => i.IsClosedTypeOf(typeof(IMessageHandler<>))); 
     if (handlerInterfaces.Any()) 
      builder.RegisterType(componentType).As(handlerInterfaces); 
    } 
} 

To gwarantuje, że każde wystąpienie componentType nigdy nie zaobserwowano przez budowniczego wcześniej, w ramach tej pętli foreach. Oznacza to, że biorąc pod uwagę, że jest to jedyny moduł używany do budowy Kontenerów, a każdy Kontener jest budowany tylko raz i nigdy nie jest aktualizowany, każdy komponent w systemie zostanie zarejestrowany w danym Kontenerze dokładnie jeden raz. Typowe interfejsy, takie jak IDisposable, IEnumerable, IComparable, IComparer, itp. Będą bezwartościowe, aby spróbować rozwiązać; rozwiążą instancję ostatniej klasy, która miała ten interfejs.

Jeśli musisz sprawdzić, czy interfejs nigdy nie był zarejestrowany, lub że ten kod działa również, gdy używasz ContainerBuilder do aktualizacji() istniejącego kontenera, po prostu zatrzymaj to, co robisz, ponieważ masz zamiar stworzyć beznadziejny bałagan, którego nigdy nie będziesz w stanie właściwie utrzymać.

+0

To powstało, ponieważ mam mechanizm podwójnego wywoływania dla wtyczek (to znaczy, że są one dostarczane klasie, która udostępnia metody rejestrowania i wewnętrznie dodaje je do konstruktora). Jest to ładnie i czysto i można go używać do rejestrowania procedur obsługi, ale szukałem sposobu, aby nie wymuszać, aby wtyczki jawnie rejestrowały wszystkie swoje programy obsługi (używając tego modułu w powłoce). Działa to również dobrze, z wyjątkiem sytuacji, gdy komponent jest zarejestrowany w wysyłce, ale jest także narzędziem obsługi komunikatów (zwłaszcza jeśli różne są okresy istnienia). – JRoughan

+0

Nie ma problemu z wieloma interfejsami istniejącymi w systemie (w rzeczywistości jest to oczekiwane). Nie ma również aktualizacji istniejących kontenerów ani zależności od rejestracji. Prawdopodobnie nie wyjaśniłem scenariusza tak dobrze, jak tylko mogłem, ale nie jest tak źle, jak prawdopodobnie myślisz. – JRoughan

+0

O, a allTypesInAllAvailableAssembly istnieje tylko w próbie SO. W prawdziwym świecie dostępne typy są dostarczane przez inną klasę z pewnymi sprytami. – JRoughan

Powiązane problemy