This project is read-only.

Custom configuration verification

Jan 17, 2014 at 3:39 PM
Edited Jan 17, 2014 at 8:04 PM
I'd like to be able to set up validation scripts within the container that I can include as part of the container verification.

We already have the verification that all registered types can be resolved - what I am suggesting here is adding custom verifications that certain types resolve in a certain way - giving some confidence that the composition root has not been "broken".

So a really simple example. Here's a basic configuration that includes a decorator with a predicate constraint:
private Container GetConfiguredContainer()
{
    var container = new Container();

    container.RegisterOpenGeneric(
        typeof(ICommandHandler<>), 
        typeof(CommandHandler<>));

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

    container.RegisterDecorator(
        typeof(ICommandHandler<>), 
        typeof(LoggingCommandHandlerDecorator<>),
        context => context.ServiceType != typeof(ICommandHandler<A>));

    return container;
}
I can have the following tests (these are obviously unit tests but I am suggesting there be some way to plug these into the container as actions)
[Test]
public void GetInstance_ICommandHandler_A_IsNotDecorated()
{
    var container = GetConfiguredContainer();

    var instance = container.GetInstance<ICommandHandler<A>>();

    instance
        .Should().BeOfType<CommandHandlerA>();
}

[Test]
public void GetInstance_ICommandHandler_B_IsDecorated()
{
    var container = GetConfiguredContainer();

    var instance = container.GetInstance<ICommandHandler<B>>();

    instance
        .Should().BeOfType<LoggingCommandHandlerDecorator<B>>()
        .And
        .Should().BeDecorating(decorated => 
            decorated.Should().BeOfType<ICommandHandler<B>>());
}
So in reality something like this:
[Test]
public void Container_IsValid()
{
    var container = GetConfiguredContainer();

    container.RegisterVerification<ICommandHandler<A>>(instance => 
        instance.Should().BeOfType<CommandHandlerA>());

    container.RegisterVerification<ICommandHandler<B>>(instance =>
        instance
            .Should().BeOfType<LoggingCommandHandlerDecorator<B>>()
            .And
            .Should().BeDecorating(decorated => 
                decorated.Should().BeOfType<ICommandHandler<B>>()));

    container.Verify();
    var results = Analyzer.Analyze(container);

    results.Length.Should().Be(0, Environment.NewLine +
        string.Join(Environment.NewLine,
            from result in results
            select result.Description));
}

Here's the rest of the code for completeness
public interface ICommandHandler<TCommand>
{
    void Execute();
}

public class A { }
public class B { }

public class CommandHandler<TCommand> :
    ICommandHandler<TCommand>
{
    public void Execute() { }
}

public class CommandHandlerA : ICommandHandler<A>
{
    public void Execute() { }
}

public class LoggingCommandHandlerDecorator<TCommand> :
    ICommandHandler<TCommand>
{
    public LoggingCommandHandlerDecorator(ICommandHandler<TCommand> decorated) { }

    public void Execute() { }
}
Jan 17, 2014 at 3:55 PM
Having such method on the container sounds rather awkward. I'm not sure what the advantage of such method would be over doing this inside unit tests.

Face it Peter, you'll have to write unit tests anyway ;-)
Jan 17, 2014 at 4:28 PM
You're probably right - I guess I mixed a requirement and a solution.

How would I implement this piece of logic - i.e. when given an instance how can I traverse the decorator chain? Or is this something I can get from Registration or InstanceProducer?
.BeDecorating(decorated => decorated.Should().BeOfType<ICommandHandler<B>>());
Jan 17, 2014 at 5:39 PM
Does this question help?
Jan 17, 2014 at 8:07 PM
Edited Jan 17, 2014 at 8:09 PM
You can get to the relevant information of the decorator chain by creating a test decorator to wrap all other registered decorators and intercepting the DecoratorPredicateContext in the callback of RegisterDecorator :-)
[Test]
public void GetInstance_ICommandHandler_A_DecoratorPredicateContextContainsDecoratorChainDetails()
{
    DecoratorPredicateContext context = null;

    var container = GetConfiguredContainer();
    container.RegisterDecorator(
        typeof(ICommandHandler<>), 
        typeof(CommandHandlerDecoratorWrapper<>),
        c => { context = c; return true; });

    var instance = container.GetInstance<ICommandHandler<A>>();

    context.AppliedDecorators.Any().Should().BeFalse();
}

[Test]
public void GetInstance_ICommandHandler_B_DecoratorPredicateContextContainsDecoratorChainDetails()
{
    DecoratorPredicateContext context = null;

    var container = GetConfiguredContainer();
    container.RegisterDecorator(
        typeof(ICommandHandler<>), 
        typeof(CommandHandlerDecoratorWrapper<>),
        c => { context = c; return true; });

    var instance = container.GetInstance<ICommandHandler<B>>();

    context.AppliedDecorators.Count.Should().Be(1);
}

private class CommandHandlerDecoratorWrapper<TCommand> : ICommandHandler<TCommand>
{
    private readonly ICommandHandler<TCommand> decorated;

    public CommandHandlerDecoratorWrapper(ICommandHandler<TCommand> decorated)
    { 
        this.decorated = decorated; 
    }

    public void Execute() { }
}
Marked as answer by dot_NET_Junkie on 2/26/2014 at 1:14 PM
Jan 17, 2014 at 9:55 PM
That's the spirit :-)