Tuesday, January 25, 2011

Using Ellemy.CQRS–Check out the example project

Ok, lets use my little cqrs project. Note that this whole example is in the source for the Ellemy.CQRS on git hub

First download the Ellemy.CQRS binaries (without example) from https://github.com/downloads/elliottohara/Ellemy.CQRS/binaries.zip.

Unzip the payload and ref it from your project.

In my example project I kept things VERY  simple.

I made a simple domain object.

   1:  using System;
   2:  using Ellemy.CQRS.Event;
   3:  using Ellemy.CQRS.Example.Events;
   4:   
   5:  namespace Ellemy.CQRS.Example.Domain
   6:  {
   7:      public class  Message
   8:      {
   9:          /// <summary>
  10:          /// Creates a new instance of Message
  11:          /// </summary>
  12:          /// <param name="id"></param>
  13:          /// <param name="text"></param>
  14:          public Message(Guid id,string text)
  15:          {
  16:              Id = id;
  17:              DomainEvents.Raise(new MessageCreated(Id,text));
  18:          }
  19:          public virtual Guid Id { get; set; }
  20:          public virtual void ChangeText(string newtext)
  21:          {
  22:              DomainEvents.Raise(new MessageTextChanged(Id,newtext));
  23:          }
  24:         
  25:      }
  26:  }

It doesn’t do much, of course… The whole point here is to show how to use Ellemy.CQRS, not solve a problem domain!


Events just have the properties you’d expect.


   1:  using System;
   2:  using Ellemy.CQRS.Event;
   3:   
   4:  namespace Ellemy.CQRS.Example.Events
   5:  {
   6:      public class MessageCreated : IDomainEvent
   7:      {
   8:          public Guid MessageId { get; set; }
   9:          public string Text { get; set; }
  10:   
  11:          public MessageCreated(Guid id, string text)
  12:          {
  13:              MessageId = id;
  14:              Text = text;
  15:          }
  16:      }
  17:  }
 
When I made (for now) a single subscriber to MessageCreated. 
 

   1:  using System;
   2:  using Ellemy.CQRS.Event;
   3:  using Ellemy.CQRS.Example.Events;
   4:   
   5:  namespace Ellemy.CQRS.Example.Query
   6:  {
   7:      public class MessageReadModelWriter : 
   8:          IDomainEventHandler<MessageCreated>
   9:      {
  10:          private readonly IRepository<MessageReadModel> _repository;
  11:   
  12:          public MessageReadModelWriter(IRepository<MessageReadModel> repository)
  13:          {
  14:              _repository = repository;
  15:          }
  16:   
  17:          public void Handle(MessageCreated @event)
  18:          {
  19:              var newReadModel = new MessageReadModel {Id = @event.MessageId, Text = @event.Text};
  20:              _repository.Save(newReadModel);
  21:          }
  22:      }
  23:  }

Now, lets move to the command side. I made a simple Command to create a message


   1:  using System;
   2:  using Ellemy.CQRS.Command;
   3:   
   4:  namespace Ellemy.CQRS.Example.Commands
   5:  {
   6:      public class CreateMessage : ICommand
   7:      {
   8:          public Guid MessageId { get; set; }
   9:          public string Text { get; set; }
  10:   
  11:          public CreateMessage(Guid messageId, string text)
  12:          {
  13:              MessageId = messageId;
  14:              Text = text;
  15:          }
  16:      }
  17:  }

And then the Handler for it.


   1:  using System;
   2:  using Ellemy.CQRS.Command;
   3:  using Ellemy.CQRS.Example.Query;
   4:   
   5:  namespace Ellemy.CQRS.Example.Commands
   6:  {
   7:      public class CreateMessageHandler : ICommandExecutor<CreateMessage>
   8:      {
   9:          private readonly IRepository<MessageReadModel> _repository;
  10:   
  11:          public CreateMessageHandler(IRepository<MessageReadModel> repository)
  12:          {
  13:              _repository = repository;
  14:          }
  15:   
  16:          public void Execute(CreateMessage command)
  17:          {
  18:              var message = new MessageReadModel {Id = command.MessageId, Text = command.Text};
  19:              _repository.Save(message);
  20:          }
  21:      }
  22:  }

Now, it’s time to plug this into a UI… First, we’ve gotta bootstrap everything up. I did this right in my global.ascx, not the way I’d do it in a production app, but once again, this is for simplicity, not maintainability.


   1:   protected void Application_Start()
   2:          {
   3:              AreaRegistration.RegisterAllAreas();
   4:   
   5:              RegisterGlobalFilters(GlobalFilters.Filters);
   6:              RegisterRoutes(RouteTable.Routes);
   7:              ObjectFactory.Configure(c =>
   8:                                          {
   9:                                              c.For(typeof (IRepository<>)).Use(typeof(InMemoryCacheRepository<>));
  10:                                          });
  11:              Configure.With()
  12:                  .StructureMapBuilder(ObjectFactory.Container)
  13:                  .CommandExecutorsAreInAssemblyContainingType<CreateMessageHandler>()
  14:                  .HandlersAreInAssemblyContainingType<MessageReadModel>();
  15:   
  16:          }
 
Check out line 11… That’ll configure the CQRS infrastructure so that it can locate CommandExecutors and events. It’ll also wire up the appropriate structure map implementations of the Factories (see my last post on that).
 
Now lets wire up a Controller.

   1:  using System;
   2:  using System.Web.Mvc;
   3:  using Ellemy.CQRS.Command;
   4:  using Ellemy.CQRS.Example.Commands;
   5:  using Ellemy.CQRS.Example.Query;
   6:  using Ellemy.CQRS.Example.Web.Infrastructure;
   7:   
   8:  namespace Ellemy.CQRS.Example.Web.Controllers
   9:  {
  10:      public class MessageController : Controller
  11:      {
  12:          private readonly IRepository<MessageReadModel> _repository;
  13:   
  14:          public MessageController() : this(new InMemoryCacheRepository<MessageReadModel>())
  15:          {
  16:          }
  17:   
  18:          public MessageController(IRepository<MessageReadModel> repository)
  19:          {
  20:              _repository = repository;
  21:          }
  22:   
  23:          public ActionResult Index()
  24:          {
  25:              return View(_repository.GetAll());
  26:          }
  27:   
  28:          [HttpGet]
  29:          public ActionResult Create()
  30:          {
  31:              return View();
  32:          }
  33:   
  34:          [HttpPost]
  35:          public ActionResult Create(string text)
  36:          {
  37:              CommandDispatcher.Dispatch(new CreateMessage(Guid.NewGuid(), text));
  38:              return RedirectToAction("Index");
  39:          }
  40:      }
  41:  }

Really, all we care about here is the Create ActionResult. The call to CommandDispatcher.Dispatch will execute the associated hander for the message.


Honestly folks… It’s that simple! Questions? Comments?


Have fun!

No comments:

Post a Comment