jonho jonho - 3 months ago 16
C# Question

Decorators decorating base Commands

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?

Answer

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).

Comments