Going over demo CQRS code here the command and event handlers are wired up separately as below:
public interface CommandHandler<in T>
{
void Handle(T command);
}
public interface EventHandler<in T>
{
void Handle(T @event);
}
bus = BusSetup.StartWith<Conservative>()
.Apply<FlexibleSubscribeAdapter>(a =>
{
a.ByInterface(typeof(IHandleEvent<>));
a.ByInterface(typeof(IHandleCommand<>));
})
.Construct();
I am using an IoC container hooked in with membus and it works a dream by implementing the IEnumerable<object> GetAllInstances(Type desiredType)
interface with my container, however unlike the demo with this method of registration I cannot split out the interfaces for separate commands and events:
this.Bus = BusSetup.StartWith<Conservative>()
.Apply <IoCSupport>(c =>
{
c
.SetAdapter(SimpleInjectorWiring.Instance)
.SetHandlerInterface(typeof(CommandHandler<>))
/*.SetHandlerInterface(typeof(EventHandler<>))*/;
// only CommandHandler or EventHandler can be used - not both
})
.Construct();
Can anyone please let me know if there any way around this so we can register for an arbitrary number of types?
I am afraid that the current version of MemBus cannot do that - for no particular reason, mind you. I know that it makes sense to be able to distinguish between Events and Commands, even though the underlying infrastructure is the same.
The only workaround right now is to use a single interface to hook the IOC into MemBus.
If such a feature should be introduced into MemBus one has to think how the lookup mechanism into the IOC Container should look like. It would probably have to request all handlers of all interfaces, or some way to categorize / distinguish between event and command "messages" would have to be introduced.
I just set this up for a proof of concept because I use the following convention per the Microsoft CQRS Journey guidelines:
I wanted use the IOC container's (SimpleInjector) API to enforce the convention as it forces you to make single vs multi handlers registrations explicit by design. Now, my IOC container will throw an Exception anytime two handlers for the same command are accidentally registered.
To get MemBus to support this convention, I needed to create my own ISetup, ISubscriptionResolver, and IoCAdapter (starting with the code from IoCSupport, IoCBasedResolver, and IocAdapter respectively). I also had to create a new IocAdapter interface that also supports the singular GetInstance() method; now the interface roughly matches the System.Web.Http.Dependencies.IDependencyScope interface (GetService and GetServices).
// Setup
return BusSetup
.StartWith<Conservative>()
.Apply<CommandingEventingSupport>(
adapter =>
{
adapter.SetAdapter(new MemBusSimpleInjectorAdapter(container));
adapter.SetCommandHandlerInterface(typeof(IHandleCommand<>));
adapter.SetEventHandlerInterface(typeof(IHandleEvent<>));
adapter.SetCommandTest(obj => obj is IDomainCommand);
})
.Construct();
And then the resolver dispatches commands to the GetInstance and events to GetAllInstances...
// Command vs Event
public IEnumerable<ISubscription> GetSubscriptionsFor(object message)
{
bool isCommand = _isCommandFunc(message);
Type typeToCreate = isCommand
? _commandHandlerType
: _eventHandlerType;
var handlesType = ConstructHandlesType(typeToCreate, message.GetType());
var mi = handlesType.GetRuntimeMethods().First();
return isCommand
? new[] { mi.ConstructSubscription(_adapter.GetInstance(handlesType)) }
: _adapter.GetAllInstances(handlesType).Select(mi.ConstructSubscription);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With