5

I am trying to implement a consumable library that has read/write Application services for each Domain in the context of CQRS. A Command Bus (or Dispatcher, or whatever it can be called in this case) interface may or may not be exposed, but implementations should be abstracted from consumers to encourage programming toward the contracts that the interfaces define. I do not want to require consumers of the library to have to set up the library in their DI framework beyond using standard conventions, so the DI framework used should't matter (requiring convention-based DI is outside of the scope of this problem).

internal interface ICommandMessage
{
    Guid Id { get; }
    DateTime DateRequestedUtc { get; }
}
internal class BaseCommandMessage
{
    /*... Implementation of ICommandMessage for common command data ...*/
}

internal class ExampleCommand : BaseCommandMessage
{
    /*... Additional data required for command ...*/
}

internal class AnotherExampleCommand : BaseCommandMessage
{
    /*... Additional data required for command ...*/
}

internal interface ICommandHandler<in TCommand> where TCommand : class, ICommandMessage
{
    Task HandleAsync(TCommand command);
}

internal class ExampleCommandHandler : ICommandHandler<ExampleCommand>, ICommandHandler<AnotherExampleCommand>
{
    Task HandleAsync(ExampleCommand command){/*...*/}
    Task HandleAsync(AnotherExampleCommand command){/*...*/}
}

public interface ICommandBus
{
    void Register<TCommand>(ICommandHandler<TCommand> handler) where TCommand : class, ICommandMessage;
    void Dispatch(ICommandMessage command);
}

public interface IDomainWriteService
{
    void Save(int id);
    /*... some other read methods ...*/
}

internal class SomeDomainWriteService
{
    private readonly ICommandBus _Bus;

    public SomeDomainWriteService(ICommandBus bus)
    {
        _Bus = bus;
    }

    public void Save(int id)
    {
        //This will change depending on how ExampleCommand is implemented, etc
        _Bus.Dispatch(new ExampleCommand());
    }
}

The main issue is in the fact that I would like internal implementations of ICommandHandler to be auto-registered with the Command Bus somehow, but constructors don't take generics, as in the following implementation:

internal public class DependencyInjectedCommandBus : ICommandBus
{
    private readonly Dictionary<Type, Action<ICommandMessage>> _handlers = new Dictionary<Type, Action<ICommandMessage>>();

    public DependencyInjectedCommandBus(List<ICommandHandler<TCommand>> handlers)
    {
        handlers.forEach(h => Register<TCommand>(h));
    }

    public void Register<TCommand>(ICommandHandler<TCommand> handler) where TCommand : class, ICommandMessage
    {
        var type = typeof (TCommand);
        if (_Handlers.ContainsKey(type))
        {
            throw new InvalidOperationException(string.Format("Handler exists for type {0}.", type));
        }
        _Handlers[type] = async command => await handler.HandleAsync((TCommand)command);
    }

    public void Dispatch(ICommandMessage command)
    {
        var type = command.GetType();
        if(!_Handlers.ContainsKey(type)){ return; }
        var handler = _Handlers[type];
        handler(command);
    }
}

Using a DI container (in this case, Ninject), an implementation without allowing for registration might look like this, provided ICommandBus changed a bit:

internal class NinjectCommandBus : ICommandBus
{
    private readonly IKernel _Kernel;

    public NinjectCommandBus(IKernel kernel)
    {
        _Kernel = kernel;
    }

    public void Register<TCommand>(ICommandHandler<TCommand> handler) where TCommand : class, ICommandMessage
    {
        throw new NotImplementedException();
    }

    public async Task DispatchAsync<TCommand>(TCommand command) where TCommand : class, ICommandMessage
    {
        var handler = _Kernel.Get<ICommandHandler<TCommand>>();
        await handler.HandleAsync(command);
    }
}

I have also read articles like this one on Mark Seeman's blog that describe ways to do it without Service Location or depending on a DI container (via "poor man's DI") however I could not get that sort of solution working for me via Ninject at all (let alone in some way using conventions or without depending on DI to do the work for me), and seems to require a bit more "boiler" code just to wire things up.

Any advice on how to potentially proceed with this without having to explicitly register handlers somewhere? Is my thinking about allowing extensibility with registration of command handlers even valid?

  • 1
    I recommend reading [this article](https://cuttingedge.it/blogs/steven/pivot/entry.php?id=91) which explains exactly this with simple injector – Sam Holder Jun 09 '15 at 18:35
  • About the async programming model you are using, please make sure the added complexity is worth the costs. Take a look at this for more information: https://codereview.stackexchange.com/questions/84379/viewmodel-creator-design/84402#84402 – Steven Jun 10 '15 at 08:13
  • @SamHolder: while I appreciate the link, it still doesn't really solve the core issue at hand, which is injecting a command bus into the Application Services that determines the handler required for the command and Dispatches it to where it needs to go instead of explicitly injecting each handler into the Application Service (though that could be a solution that cuts out the bus/dispatcher middleman...). – MonkeyJamboree Jun 10 '15 at 12:24
  • 1
    @Steven: In my case, the reason for having async is that command handlers could (and some do) call external web services. I believe the topic of sync vs. async is outside of the scope of this conversation, but I'd like to have a more in-depth discussion about the pros/cons at some point... – MonkeyJamboree Jun 10 '15 at 12:28
  • 1
    @user1893186 please see the answer to [this question](http://stackoverflow.com/questions/23564330/configure-decorators-for-generic-interfaces-and-inject-all-instances-to-construc) which discusses options for creating a `CommandDispatcher` which has the responsibility for delivering the messages to the right handler. it links to a folow up article of the one I posted. – Sam Holder Jun 10 '15 at 12:32
  • @SamHolder I did have things set up that way with a class in my composition root, however that doesn't quite work for me because it creates an indirect dependency on using a DI framework to function *and* for it to implement the bus that's used inside the library. That just seems "wrong" to me. (I suppose the way the library is designed it already has that, but I'm trying to avoid any custom code in consumers of the library and just allow named conventions to resolve dependencies.) – MonkeyJamboree Jun 10 '15 at 13:00
  • @MonkeyJamboree one of the commentators has similar concerns and its pointed out that you could inject an enumerable of ICommandHandlers instead on the container and find the appropriate handler from the enumerable instead of letting the container resolve it. The comment points out that this may have issues, but I believe they could be resolved with a hashset for the command handlers keyed by type. – Sam Holder Jun 10 '15 at 13:10
  • @SamHolder hmm. I am attempting to inject an enumerable as suggested, but the enumerable is always empty (perhaps because of the structure of my Command objects, or because the handler implementations implement ICommandHandler and not ICommandHandler). I'm starting to believe that this is way more trouble than it's worth :-\ – MonkeyJamboree Jun 10 '15 at 13:53
  • you want everything that implement the open generic type `ICommandHandler<>` I believe – Sam Holder Jun 10 '15 at 13:58
  • @MonkeyJamboree: There is no problem in injecting the container into the `CommandBus` implementation, because this implementation will be part of your Composition Root, that already depends on that container. Just define the `ICommandBus` abstraction in your application and the implementation **inside** the composition root, just as [this article](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=92) describes with the `QueryProcessor`. – Steven Jun 10 '15 at 15:04
  • I understand that in using the DI-container-tied CommandBus implementation would be part of the composition root. However, that puts an (unspoken) dependency upon library consumers to implement ICommandBus themselves to even use the library. I think for immediate purposes, doing it in the composition will work, but I would like to have a default implementation that doesn't rely on building something external to the library for it to function. Thanks for all the replies on this so far, it's been helpful to think about it in different ways. I'm still open to more suggestions on this. – MonkeyJamboree Jun 10 '15 at 15:33

1 Answers1

4

If you don't mind scanning assemblies for command handlers, here is a simple solution that works withou a DI-container.

namespace SimpleCqrs {
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Reflection;
  using System.Threading.Tasks;

  public interface ICommandMessage {
    Guid Id { get; }
    DateTime DateRequestedUtc { get; }
  }

  internal abstract class BaseCommandMessage : ICommandMessage {
    protected BaseCommandMessage() {
      DateRequestedUtc = DateTime.UtcNow;
      Id = Guid.NewGuid();
    }

    public DateTime DateRequestedUtc {
      get; private set;
    }

    public Guid Id {
      get; private set;
    }
  }

  internal class ExampleCommand : BaseCommandMessage {
    public string Message { get; set; }
  }

  internal class AnotherExampleCommand : BaseCommandMessage {
    public string Message { get; set; }
  }

  internal interface ICommandHandler<in TCommand> where TCommand : class, ICommandMessage
  {
    Task HandleAsync(TCommand command);
  }

  internal class WriteService : ICommandHandler<ExampleCommand>, ICommandHandler<AnotherExampleCommand>
  {
    public Task HandleAsync(AnotherExampleCommand command) {
      return Task.Run(() => {
        Console.WriteLine(command.Message);
      });
    }

    public Task HandleAsync(ExampleCommand command)
    {
      return Task.Run(() =>
      {
        Console.WriteLine(command.Message);
      });
    }
  }

  public interface ICommandBus
  {
   void Dispatch(ICommandMessage command);
  }

  public class SimpleCommandBus : ICommandBus
  {
    Dictionary<Type, Type> handlers;
    MethodInfo dispatchCommand;

    public SimpleCommandBus()
    {
      this.handlers = RegisterCommandHandlers();
      this.dispatchCommand = GetType().GetMethod("DispatchCommand", BindingFlags.NonPublic | BindingFlags.Instance);
    }

    public void Dispatch(ICommandMessage command)
    {
      var cmdType = command.GetType();
      var handler = Activator.CreateInstance(handlers[cmdType]);
      var genericMethod = dispatchCommand.MakeGenericMethod(cmdType);
      genericMethod.Invoke(this, new object[] { handler, command });
    }

    async void DispatchCommand<T>(ICommandHandler<T> handler, T command) where T : class, ICommandMessage
    {
      await handler.HandleAsync(command);
    }

    Dictionary<Type, Type> RegisterCommandHandlers()
    {
      Func<Type, bool> isCommandHandler = t => 
        t.GetInterfaces()
         .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICommandHandler<>));

      Func<Type, IEnumerable<Tuple<Type, Type>>> collect = t =>
        t.GetInterfaces().Select(i =>       
          Tuple.Create(i.GetGenericArguments()[0], t));

      return Assembly.GetCallingAssembly()
                     .GetTypes()
                     .Where(t => !t.IsAbstract && !t.IsGenericType)
                     .Where(isCommandHandler)
                     .SelectMany(collect)
                     .ToDictionary(x => x.Item1, x => x.Item2);
    }
  }


  class Program
  {
    static void Main(string[] args)
    {
      var bus = new SimpleCommandBus();
      bus.Dispatch(new ExampleCommand { Message = "Hello" });
      bus.Dispatch(new AnotherExampleCommand { Message = "World" });
      Console.ReadKey();
    }
  }
}
Per
  • 1,061
  • 7
  • 11