Question

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?

Was it helpful?

Solution

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

OTHER TIPS

You can decorate your classes this way as long as you are following one simple rule - your consumers are always expecting ICommandHandler<,>

So, if your constructor is written like this

public class Consumer
{
    public Consumer(ICommandHandler<CommandStub, ResultStub> handler)
    {
    }
}

Your implementations are registered something like this (i.e. as ICommandHandler's)

container.RegisterManyForOpenGeneric(
    typeof(ICommandHandler<,>), 
    typeof(ICommandHandler<,>).Assembly);

And your decorator is registered like this

container.RegisterDecorator(
    typeof(ICommandHandler<,>),
    typeof(MockAuthorisationDecorator<,>));

then despite the fact that the implementation of MockTransactionalCommandHandler is written as inheriting from ITransactionalCommandHandler<,>

public class MockTransactionalCommandHandler : 
    ITransactionalCommandHandler<CommandStub, ResultStub> {
    public ResultStub Result { get { throw new NotImplementedException(); } }

    public void Handle(CommandStub command) { }
}

Your Consumer class will still be given an instance of MockTransactionalCommandHandler decorated with an instance of MockAuthorisationDecorator

A slight complication is introduced (with a simple solution) when you have a decorator that should only wrap some of the ICommandHandler<,>'s (in this case the decorators such as MockUnitOfWorkDecorator<,>) - to get this to work as you desire you need to define a Predicate<> as part of the decorator registration.

The registration for the MockUnitOfWorkDecorator would look something like this:

container.RegisterDecorator(
    typeof(ICommandHandler<,>),
    typeof(MockUnitOfWorkDecorator<,>),
    context =>
    {
        var baseType = typeof(ITransactionalCommandHandler<,>);
        var type = baseType.MakeGenericType(
            context.ServiceType.GetGenericArguments());
        return type.IsAssignableFrom(context.ImplementationType);
    });
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top