3
votes

The Setup

I'm running a web application on .NET4.0 that is wired up using the almighty SimpleInjector3. I'm using the Command-/QueryHandler architecture described here and I have an issue with configuring a dependency for a command handler.

Sample Code

Here is a breakdown of the class structure:

interface ICommandHandler<T> 
{
    void Handle(T command);
}

enum LoggingState { Success, Failed }

interface ICommandLogger<T>
{
    void Log(LoggingState state, T command);
}

class NullCommandLogger<T> : ICommandLogger<T>
{
    void Log(LoggingState state, T command)
    {
        // Intentionally left blank
    }
}

Decorator:

/// <summary>
/// The logging command handler that gets wrapped around every
/// command handlers.
/// </summary>
class LoggingCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand>
{
    private readonly ICommandHandler<TCommand> decorated;
    private readonly ICommandLogger<TCommand> logger;

    public LoggingCommandHandlerDecorator(
        ICommandHandler<TCommand> decorated,
        ICommandLogger<TCommand> logger)
    {
        this.decorated = decorated;
        this.logger = logger;
    }

    public void Handle(TCommand command)
    {
        try
        {
            this.decorated.Handle(command);
        }
        catch (Exception)
        {
            this.logger.Log(LoggingState.Failed, command);
            throw;
        }

        this.logger.Log(LoggingState.Success, command);
    }
}

In my CompositionRoot I configure it like this:

var assembly = /* Get the assembly where the handlers are located */

// Register all explicitly defined loggers
container.Register(typeof(ICommandLogger<>), assembly);

// Register null objects for everything else
container.RegisterConditional(
    typeof(ICommandLogger<>),
    typeof(NullCommandLogger<>),
    ctx => !ctx.Handled);

// Wrap all command handlers with the logging
container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(LoggingCommandHandlerDecorator<>));

This works very well for non-generic loggers like this one:

class WorkingLogger : ICommandLogger<SomeCommand> { /* ... */ }

The Problem

Now I have a set of commands that implement a marker interface so that I can use one single logger for all of them - but this won't be picked up by the SimpleInjector:

class NotWorkingLogger<T> : ICommandLogger<T>
    where T : IMarkerInterface { /* ... */ }

I'm aware that this shouldn't be a variance issue but I've tried using the variance extensions just to be sure but to no avail.

Is there a way to configure this scenario?

1

1 Answers

2
votes

You'll just have to add the registration for NotWorkingLogger<T> explicitly as follows:

container.Register(typeof(ICommandLogger<>), assembly);

// It's added between the two other registrations
container.RegisterConditional(
    typeof(ICommandLogger<>),
    typeof(NotWorkingLogger<>),
    ctx => !ctx.Handled);

container.RegisterConditional(
    typeof(ICommandLogger<>),
    typeof(NullCommandLogger<>),
    ctx => !ctx.Handled);