I am using SimpleInjector 2.2.3.0.
I have a MVC 4.0 project and am using the decorator pattern around my Commands to manage my UnitOfWork and my Authorisation.
I have decorator which does authorisation - the IAuthorisationDecorator
. This wraps all of my ITransactionalCommandHandlers
.
(Each ITransactionalCommandHandler
is also decorated by IUnitOfWorkDecorator
.) The authorisation decorator looks like this:
public void Handle(TCommand command)
{
//authorise this command for this Iprincipal
decoratedCommandHandler.Handle(command);
}
I now want to create a INonTransactionalCommandHandler
(that doesn’t need an NHibernate session, it just does some File IO).
Note both INonTransactionalCommandHandler
and ITransactionalCommandHandler
inherit from ICommandHandler
– which looks like so:
public interface ICommandHandler<in TCommand, out TResult>
{
TResult Result { get; }
void Handle(TCommand command);
}
I don’t really want to have to create two identical AuthorisationDecorators
(transactional/non transactional). Because ultimately they decorate a base ICommandHandler
( which is implemented as either a ITransactional
or INonTransactional
).
So my question is - Is there any way to create 1 Decorator that decorates a base ICommandHandler
- but the container knows to cast up the ICommandHandler
to a ITransactionalCommandHandler
or an INonTransactionalCommandHandler
. Is there any way to do this?
If you register all command handlers by their ICommandHandler<TCommand, TResult>
interface, you can't wrap part of the handlers with a decorator that wraps an ITransactionalCommandHandler<TCommand, TResult>
. You can only apply such decorator if the handlers are explicitly registered by that ITransactionalCommandHandler<TCommand, TResult>
interface, but this is not something you should do. You don't want that, since that means that the consumers of those commands need to know whether the handlers is transactional or not, which they shouldn't care about (it's a implementation detail).
Your transactional decorator should therefore wrap an ICommandHandler<TCommand, TResult>
. If it needs access to the ITransactionalCommandHandler<TCommand, TResult>
interface, the decorator should cast the input parameter from ICommandHandler
to ITransactionalCommandHandler
.
What you need is to register your decorators based on a predicate, as follows:
// NOTE: In Simple Injector v2.x use 'ManyForOpenGeneric' instead.
container.Register(typeof(ICommandHandler<,>), myAssemblies);
container.RegisterDecorator(typeof(ICommandHandler<,>), typeof(TransactionDecorator<,>),
c => typeof(ITransactionalCommandHandler<,>)
.MakeGenericType(c.ServiceType.GetGenericArguments())
.IsAssignableFrom(c.ImplementationType));
container.RegisterDecorator(typeof(ICommandHandler<,>), typeof(AuthorisationDecorator<,>));
The predicate ensures that only command handlers are decorated that implement the ITransactionalCommandHandler<,>
.
Instead of using that interface, you might also mark the handlers with an attribute:
[Transactional]
class ShipOrderCommandHandler : ICommandHandler<ShipOrderCommand, Unit> { ... }
In that case the registration would become:
container.RegisterDecorator(typeof(ICommandHandler<,>), typeof(TransactionDecorator<,>),
c => c.ImplementationType.GetCustomAttribute<TransactionalAttribute>() != null);
Yet another option is to mark the command itself with an interface or inherit from a base class:
public class ShipOrderCommand : ICommand<Unit>, ITransactionalCommand
{
public Guid OrderId;
}
This allows you to add a generic type constraint on the TransactionDecorator<,>
and allows you to remove the predicate on the RegisterDecorator
registration:
public class TransactionDecorator<int TCommand, out TResult>
: ICommandHandler<TCommand, TResult>
where TCommand : ITransactionalCommand
{
// etc
}
Since Simple Injector understands type constraints, you can simplify the registration as follows:
container.RegisterDecorator(typeof(ICommandHandler<,>), typeof(TransactionDecorator<,>));
Do note that I don't advice this last approach in this particular case, since implementing an ITransactionalCommand
interface on the command again means that implementation details are leaking into the definition of the command. The command and its consumers don't need to know about whether transactions are needed on the command handler (and this is something that might change in the future).