bling.github.io

This blog has relocated to bling.github.io.

Tuesday, November 23, 2010

CQRS: Auto register event handlers

I’m not going to go into detail about what the deal is about event handlers in a CQRS architecture, since a quick Google/Bing search will give plenty of very good information.  What this post is about is a solution to the “how do I quickly register something to handle a bunch of events” without copying pasting all over the place. There are other solutions out there, like this one.  Here’s something I came up with (took some concepts from my post on Weak Events).

public class Aggregate
{
  private delegate void OpenEventHandler<in TTarget, in TEvt>(TTarget target, TEvt @event);
  private static readonly IDictionary<Type, OpenEventHandler<Game, IEvent>> _evtHandlers = new Dictionary<Type, OpenEventHandler<Game, IEvent>>();
   
  static Aggregate()
  {
    var methods = from m in typeof(Game).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
    let p = m.GetParameters()
            where m.Name == "ApplyEvent" && p.Length == 1 && typeof(IEvent).IsAssignableFrom(p[0].ParameterType)
            select m;
    
    var registerForwarder = typeof(Game).GetMethod("RegisterForwarder", BindingFlags.NonPublic | BindingFlags.Static);
    foreach (var m in methods)
    {
      Type eventType = m.GetParameters()[0].ParameterType;
      var forwarder = registerForwarder.MakeGenericMethod(eventType).Invoke(null, new[] { m });
      _evtHandlers[eventType] = (OpenEventHandler<Game, IEvent>)forwarder;
    }
  }
  
  private static OpenEventHandler<Game, IEvent> RegisterForwarder<TEvt>(MethodInfo method)
  {
    var invoker = typeof(OpenEventHandler<,>).MakeGenericType(typeof(Game), typeof(TEvt));
    var forwarder = (OpenEventHandler<Game, TEvt>)Delegate.CreateDelegate(invoker, null, method);
    return (g, e) => forwarder(g, (TEvt)e);
  }
 
  private void ApplyEvent(EventHappened e)
  {
    _something = e.Something;
  }
 
  public void ApplyChanges(IEnumerable<IEvent> events)
  {
    foreach (var e in events)
    {
      _evtHandlers[e.GetType()](this, e);
    }
  }
}

A couple things:

  • The registration happens in the static constructor.  This is important, because this relatively heavy cost of using reflection only happens once for the aggregate.
  • The filtering of methods is arbitrary.  I chose “ApplyEvent” here as the convention, but of course you can choose whatever you like.
  • ApplyChanges simply invokes the event handlers dictionary directly.  Assuming you’re being a good citizen with the code, accessing _evtHandlers doesn’t need a lock because once created it should never be modified.

So in summary, it finds all methods named ApplyEvent in the current class, and generates an “open delegate” which takes in an extra parameter which is the instance itself.  In this case, the instance is the aggregate, as shown in the ApplyChanges method.

So there you have it!  Excluding the lengthy LINQ query, roughly 10 lines of code to find and register all event handlers in the aggregate.  And if you’re wondering, the performance cost is negligible because there’s no reflection involved in the invocation of the handlers.  Awesome!

Monday, November 8, 2010

That Immutable Thing

Do you have some sort of ImmutableAttribute in your domain that you use to mark classes as immutable?  Have you ever needed to enforce that contract?  Checking for readonly fields isn’t enough?  Well, this weekend I had a code spike that helped solve this problem in my current project.

For this project, I’m using the NoRM driver for MongoDB, and one of the limitations of the serializer is that all types must be classes, must have a default constructor, and all properties have a public setter.  So, now the domain has a bunch of classes like this:

public class UserCreatedEvent : IEvent
{
  public string Name { get; set; }
  public UserCreatedEvent() { }
  public UserCreatedEvent(string name) { Name = name; }
}

That God for code snippets (or Resharper templates).  With so many classes like this that need to get serialized, I wanted to extra sure that no code ever calls the setter method for the Name property.  Thankfully, with some help of Mono.Cecil, it’s possible.

First off, you need to define ImmutableAttribute and that add that do classes, and in my case, it is historical domain events that get serialized to an event store.

Then, you just write a unit test which leverages the power of Mono.Cecil.  It turned out to be pretty simple.  Here’s the code:

using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
using NUnit.Framework;
namespace blingcode
{
    [TestFixture]
    public class ImmutabilityTests
    {
        private static readonly MethodDefinition[] _setterMethods;
        private static readonly AssemblyDefinition[] _assemblies;
        static ImmutabilityTests()
        {
            _assemblies = new[]
            {
                AssemblyDefinition.ReadAssembly(typeof(Something).Assembly.Location),
            };
            _setterMethods = _assemblies
                .SelectMany(a => a.Modules)
                .SelectMany(m => m.Types)
                .Where(t => t.CustomAttributes.Any(attr => attr.AttributeType.Name.Contains("ImmutableAttribute")))
                .SelectMany(t => t.Properties)
                .Where(p => p.SetMethod != null)
                .Select(m => m.SetMethod)
                .ToArray();
        }
        [Test]
        public void ClassesWith_ImmutableAttribute_ShouldNotUse_PropertySetters()
        {
            AssertForViolations(_assemblies
                                    .SelectMany(a => a.Modules)
                                    .SelectMany(m => m.Types)
                                    .Where(t => t.IsClass)
                                    .SelectMany(t => t.Methods));
        }
        [Test]
        public void ThisFixtureActuallyWorks()
        {
            var assembly = AssemblyDefinition.ReadAssembly(typeof(ImmutabilityTests).Assembly.Location);
            var type = assembly.Modules.SelectMany(m => m.Types)
                .Where(t => t.IsClass && t.FullName.Contains(GetType().FullName)).First();
            try
            {
                AssertForViolations(type.Methods);
            }
            catch (AssertionException)
            {
                Assert.Pass();
            }
        }
        private static void AssertForViolations(IEnumerable<MethodDefinition> potentialMethods)
        {
            foreach (var method in potentialMethods.Where(m => m.HasBody))
            {
                foreach (Instruction ins in method.Body.Instructions.Where(ins => ins.OpCode == OpCodes.Callvirt))
                {
                    MemberReference mr = ins.Operand as MemberReference;
                    if (mr != null)
                    {
                        var result = _setterMethods.FirstOrDefault(m => m.FullName == mr.FullName);
                        if (result != null)
                        {
                            throw new AssertionException(result + " was invoked by " + method + ", even though the type has the Immutable attribute.");
                        }
                    }
                }
            }
        }
        private void InvokeCardSetters()
        {
            // this only exists to test that the test does indeed work
            var c = new SomeImmutableClass();
            c.SomeImmutableValue = 123;
        }
    }
}

Nothing too complicated.  The main thing to look for is the callvirt method, which the C# compiler always generates for classes.  Then, you match the operand to the method definition and viola!