Ok, so my examples working pretty good. Ellemy.CQRS is doing it’s job pretty well. In fact (even though they don’t realize it), a lot of people are using it and liking it – in spite of the arguments about CQRS being “too complex”. I consider this a victory. But hey, whatever!
The way things currently work though is that all event and command handling is done in process. When I wrote the first pass, this was a strategic decision – in fact it was one of my stated goals. But, lets move this puppy to real world. Like, in a scenario where we actually want durable messaging.
So, I created a simple interface.
1: public interface IEventPublisher
2: {
3: void Publish<TDomainEvent>(TDomainEvent @event) where TDomainEvent : IDomainEvent;
4: }
and in my DomainEvents class, I made a small change in the Publish method. It now looks like this.
1: public static void Publish()
2: {
3: if (handlerActions != null)
4: {
5: handlerActions.ForEach(a => a());
6: }
7: var publisher = Configure.CurrentConfig.EventPublisher;
8: if(unpublishedEvents != null){
9: foreach (var unpublishedEvent in unpublishedEvents)
10: {
11: publisher.Publish(unpublishedEvent);
12: }
13: unpublishedEvents.Clear();
14: }
15: }
I just added lines 7-12. I can clean this up a lot (and I will), but I wanted to leave this method all inline so you guys can see what it looks like. Line 7 grabs the currently configured instance of IEventPublisher. I wrote this one really quick to use if you don’t care to publish to remote systems.
1: public class NoOpPublisher : IEventPublisher
2: {
3: public void Publish<TDomainEvent>(TDomainEvent @event) where TDomainEvent:IDomainEvent
4: {
5:
6: }
7: }
And made that the default by just newing one up in my Configuration class.
Lets get to the good stuff now. I’m a big NServiceBus fan, so I wanna make a implementation that pushes out a NSB message for the events. NSB requires us to mark Messages with IMessage. I don’t want to bleed that into my domain, so we’re gunna make a quick class that is an IMessage, but contains the DomainEvent so that subscribers can get to it.
It looks like this.
1: [Serializable]
2: public class EventMessage<T> : IMessage
3: where T : IDomainEvent
4: {
5: public EventMessage(T @event)
6: {
7: Payload = @event;
8: }
9: public EventMessage(){}
10: /// <summary>
11: /// Gets or sets transported event.
12: /// </summary>
13: public T Payload { get; set; }
14: }
So, next we’re gunna create an implementation of IEventPublisher that sends this puppy off to the bus, it’s really really simple.
1: public class NServiceBusPublisher : IEventPublisher
2: {
3: private readonly IBus _bus;
4:
5: public NServiceBusPublisher(IBus bus)
6: {
7: _bus = bus;
8: }
9:
10: public void Publish<TDomainEvent>(TDomainEvent @event) where TDomainEvent:IDomainEvent
11: {
12: var message = new EventMessage<TDomainEvent>(@event);
13: _bus.Send(message);
14: }
15: }
I just did a Send through NSB for now. I’ll move that to a publish once I get commands sent off, so that I won’t be publishing from a website. See here for why that’s a bad idea.
Next up, how to we tell Ellemy.CQRS to use this puppy? In my fluent Configure class I simply added this.
1: public Configuration PublishEventsWith(IEventPublisher publisher)
2: {
3: EventPublisher = publisher;
4: return this;
5: }
6: internal IEventPublisher EventPublisher { get; private set; }
And in the assembly that contains the NSB stuff, I wrote an extension method for the configure class like so.
1: public static class ConfigurationExtensions
2: {
3: public static Configuration NServiceBusPublisher(this Configuration configuration,IBus bus)
4: {
5: configuration.PublishEventsWith(new NServiceBusPublisher(bus));
6: return configuration;
7: }
8: }
Back to my website, I change my bootstrap code to look like this.
1: Configure.With()
2: .StructureMapBuilder(ObjectFactory.Container)
3: .CommandExecutorsAreInAssemblyContainingType<CreateMessage>()
4: .HandlersAreInAssemblyContainingType<MessageReadModel>()
5: .NServiceBusPublisher(ObjectFactory.Container.GetInstance<IBus>());
That’s really all we’ve gotta do to get Ellemy.CQRS to work.
But we’ve gotta now make NServiceBus play nice. Since we’re only sending one type of message I set my config for the client like this.
1: <UnicastBusConfig>
2: <MessageEndpointMappings>
3: <add Messages="Ellemy.CQRS.Publishing.NServiceBus.EventMessage`1[[Ellemy.CQRS.Event.IDomainEvent, Ellemy.CQRS]],Ellemy.CQRS.Publishing.NServiceBus" Endpoint="myserverinputqueue" />
4: </MessageEndpointMappings>
5: </UnicastBusConfig>
Now, when we add a message through the example website, we see this in MSMQ
Ok, we know we’re now sending off the message! Next blog, I’ll write a subscriber that’ll print stuff out to the console that it received the message. Or you can just git the code…
Have fun with it!
No comments:
Post a Comment