Autofac i open generic types: Application Events revisited

5

Ostatnio poznaję kontener DI Autofac i baaardzo mi się on podoba – nie tylko nazwa, funkcjonalność także. Ten post rozpoczyna paczkę kilku ciekawych (mam nadzieję:) ) postów pokazujących, jak przy pomocy Autofac zbudować “samoskładającą się” aplikację.

Dzisiaj na dobry początek wrócimy do koncepcji, którą zerżnąłem od Udiego a przedstawiłem w poście Application Events (tam tez więcej linków w temacie samych zdarzeń). W opisanym przeze mnie sposobie mechanizm ten wymagał ręcznej rejestracji każdego handlera za pomocą klasy ApplicationEventsManager, na przykład tak:

  1:  ApplicationEventsManager.OnEvent<UserForgotPassword>().UseHandler<SendReminder>();

Mając takie rejestracje w momencie wywołania zdarzenia:

  1:  ApplicationEventsManager.Raise(new UserForgotPassword(user));

Manager przejeżdża się po prostu po swojej wewnętrznej liście handlerów i wykonuje te, które potrafią dane zdarzenie obsłużyć:

  1:  public static class ApplicationEventsManager
  2:  {
  3:  	private static readonly IList<object> _handlers = new SynchronizedCollection<object>();
  4:  
  5:  	public static void Raise<TEvent>(TEvent e) where TEvent : IApplicationEvent
  6:  	{
  7:  		foreach (var handler in _handlers.OfType<Handles<TEvent>>())
  8:  		{
  9:  			handler..Handle(e);
 10:  		}
 11:  	}
 12:  	//...

(po więcej kodu i wyjaśnień zapraszam oczywiście do wspomnianej notki)

Działa, fajnie wygląda, daje dużą kontrolę, ale można by spróbować inaczej. Po co ręcznie rejestrować handlery? O tego właśnie mamy przecież kontenery DI/IoC! Na dobrą sprawę kod CAŁEJ klasy ApplicationEventsManager, pozbawionej instrukcji pozwalających na ręczną rejestrację, mógłby wyglądać tak:

  1:  public static class ApplicationEventsManager
  2:  {
  3:  	public static void Raise<T>(T e) where T : IApplicationEvent
  4:  	{
  5:  		foreach (var handler in Container.Resolve<IEnumerable<Handles<T>>>())
  6:  		{
  7:  			handler.Handle(e);
  8:  		}
  9:  	}
 10:  }

Nic prostszego! Co prawda takie coś nawet na miano "managera" nie zasługuje, ale…:).

Z Aufoaq wystarczy zaimplementować klasę modułu, która wykryje wszystkie implementacje handlerów z wykorzystaniem otwartych typów generycznych. Brzmi groźnie? To zobaczmy:

  1:  public class ApplicationEventsRegistrationModule : Module
  2:  {
  3:  	protected override void Load(ContainerBuilder builder)
  4:  	{
  5:  		builder
  6:  		.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
  7:  		.AsClosedTypesOf(typeof(Handles<>));
  8:  	}
  9:  }

I.. to wszystko! Taki moduł dodajemy do Autofac, a reszta dzieje się sama. Każdy handler w całym systemie (wszystkich załadowanych dllkach) będzie widoczny – dzięki metodzie RegisterAssemblyTypes. Piękne.

Po więcej info o open generic types odsyłam do Google’a.

Nie przegap kolejnych postów!

Dołącz do ponad 9000 programistów w devstyle newsletter!

Tym samym wyrażasz zgodę na otrzymanie informacji marketingowych z devstyle.pl (doh...). Powered by ConvertKit
Share.

About Author

Programista, trener, prelegent, pasjonat, blogger. Autor podcasta programistycznego: DevTalk.pl. Jeden z liderów Białostockiej Grupy .NET i współorganizator konferencji Programistok. Od 2008 Microsoft MVP w kategorii .NET. Więcej informacji znajdziesz na stronie O autorze. Napisz do mnie ze strony Kontakt. Dodatkowo: Twitter, Facebook, YouTube.

5 Comments

  1. Nie bylbym soba, gdybym nie wspomnial, ze Autofa nie jest tu wyjatkiem i Castle Windsor tez fantastycznie radzi sobie ze wspomnianym zagadnieniem, o czym nawet niedawno blogowalem ;)

  2. @Krzysztof Koźmic:
    Nie wątpię:). Wczesniej znalem tylko Unity i postanowilem (w sumie także za sprawą twoich postów i tweetów) poszerzyc horyzonty. Kolejność: Autofac -> Ninject -> Castle.

  3. AppDomain.CurrentDomain.GetAssemblies() ??
    A co z assemblies, które nie są załadowane?
    Tak z ciekawości chętnie zobaczę jakby to wyglądało ze skanowaniem np. folderu bin w ASP.NET.
    StructureMap ma ponoć bardzo duże możliwości skanowania, natomiast Ninject ma na nim wzorowany tzw. extension.