Wracam po świąteczno-noworocznej przerwie z drugą częścią tutoriala NServiceBus.
Drugi z przykładów, które chciałbym z Wami omówić to demo subskrypcji. W katalogu z przykładami NServiceBus znajdziecie go pod nazwą „PubSub”. Solution składa się z 4 projektów.
MyMessages zawiera definicje wymienianych komunikatów. Zwróćcie uwagę, że są tam dwa elementy:
interfejs IEvent oraz
klasa EventMessage z niego dziedzicząca. Skąd to i po co? I dlaczego to wytłuszczenie? Otóż NServiceBus posiada unikalną własność — umożliwia definiowanie
komunikatów jako interfejsów oraz obsługuje ich dziedziczenie (zarówno między interfejsami, jak i między interfejsami i klasami). Jak to działa? Jeśli zdecydowałem się odbierać (czy to przez subskrypcje, czy też „klasycznie” – request/response) pewien typ komunikatu, to mój endpoint będzie odbierał także
wszystkie komunikaty, których typy dziedziczą z podanego.
Ale skończymy to teoretyzowanie i popatrzmy na przykład.
MySubscriber1 zawiera handler dla komunikatu typu
EventMessage. NServiceBus automatycznie przy starcie wykrywa ten fakt, odnajduje w pliku konfiguracyjnym adres kolejki wejściowej instancji NSB publikującej ten komunikat i zgłasza się do niej jako subskrybent.
MySubscriber2 wykorzystuje możliwość własnej inicjalizacji instancji NSB i wymusza pominięcie automatycznej subskrypcji.
1 public class EndpointConfig : IConfigureThisEndpoint, IWantCustomInitialization
2 {
3 public void Init()
4 {
5 NServiceBus.Configure.With()
6 .CastleWindsorBuilder() // just to show we can mix and match containers
7 .XmlSerializer()
8 .MsmqTransport()
9 .IsTransactional(true)
10 .UnicastBus()
11 .DoNotAutoSubscribe() //managed by the class Subscriber2Endpoint
12 .LoadMessageHandlers();
13 }
14 }
Jest ona zrealizowana „manualnie” w klasie
Subscriber2Endpoint. MySubscriber2 zawiera handler dla komunikatów typu
IEvent.
„Skomplikowana” logika zawarta w
Publisherze
var eventMessage = publishIEvent ? Bus.CreateInstance<IEvent>() : new EventMessage();
sprawia, że co drugi raz wysyłany jest komunikat typu
EventMessage, a co drugi — anonimowa (dynamicznie generowana) implementacja
IEvent. Zastanówmy się wobec tego jak zachowają się subskrybenci. Subscriber2, któremu obojętne co przetwarza, pod warunkiem, że to „coś” stosuje się do kontraktu
IEvent będzie reagował
na każdy opublikowany komunikat. Subscriber1 jest selektywny — nie interesuje go „byle jaka” dynamiczna implementacja
IEvent. On chce tylko
EventMessage. Będzie więc reagował na
co drugi komunikat. Prawda, że sprytne?
Co ważne, decyzja kto jest zainteresowany danym komunikatem następuje
na poziomie publikującego, a nie subskrybującego. Publisher nie wysyła do MySubscriber1 anonimowych implementacji
IEvent, gdyż wie, że ten sobie tego nie życzy.
Ostatnim elementem przykładu jest implementacja interfejsu
IAuthorizeSubscribtions. Pozwala ona na określenie, na podstawie danych o nadawcy, czy pozwolić na realizację danego żądania subskrypcji. Mechanizm ten pozwala skutecznie ograniczyć zakres publikacji do wyłącznie zaufanych maszyn i/lub użytkowników.