3

I have a project that is using a decorator convention to wrap command handlers with logging decorators via interception of open generic types in StructureMap 2.6. However, I'm having difficulty figuring out the best way to implement the equivalent functionality in StructureMap 3 so that I can complete the upgrade.

Here's the code from StructureMap 2.6. First, in my IoC class I have a scanning policy set up to resolve the command handlers:

scan.ConnectImplementationsToTypesClosing(typeof(ICommandHandler<>));

Next, I have a decorator convention, which is added to the IoC's scanning conventions, that wires up the decorator interception:

public class CommandLoggingDecoratorConvention : IRegistrationConvention
{
    public void Process(Type type, Registry registry)
    {
        var interfaceTypes = type.GetInterfaces();

        foreach (var interfaceType in interfaceTypes)
        {
            if (interfaceType.IsGenericType
                && interfaceType.GetGenericTypeDefinition() == typeof(ICommandHandler<>))
            {
                var arguments = interfaceType.GetGenericArguments();

                var closedType = typeof(CommandHandlerLoggingDecorator<>)
                    .MakeGenericType(arguments);

                registry.For(interfaceType)
                    .EnrichWith((c, p) => Activator.CreateInstance(
                        closedType, 
                        p, 
                        c.GetInstance<IMessageLoggingHelper>(), 
                        c.GetInstance<ILog>()));
            }
        }
    }
}

Then, we have a command bus which maps a specific command to a command handler and calls the Execute method on the logging decorator (which is wrapping the command handler) which in turns calls the Execute method on the command inside of the decorator:

public class CommandBus : ICommandBus
{
    public static IContainer Container;

    public void Execute(ICommand command)
    {
        var handlerType = typeof (ICommandHandler<>)
            .MakeGenericType(command.GetType());

        dynamic handler = Container
            .GetAllInstances(handlerType)
            .Cast<dynamic>()
            .Single();

        handler.Execute((dynamic) command);
    }
}

I have been able to make this work in StructureMap 3 by replacing my decorator convention with an interceptor policy and adding the interceptor policy in the IoC class.

Here's the interceptor policy:

public class CommandLoggingDecoratorPolicy : IInterceptorPolicy
{
    public string Description { get; private set; }

    public IEnumerable<IInterceptor> DetermineInterceptors(Type pluginType, Instance instance)
    {
        if (pluginType == typeof (ICommandHandler<>))
            yield return new DecoratorInterceptor(
                typeof(ICommandHandler<>),
                typeof(CommandHandlerLoggingDecorator<>));
    }

And here's the code that adds it to the IoC's interceptor policies:

x.Policies.Interceptors(new CommandLoggingDecoratorPolicy());

However, when I call Container.GetInstance (in my CommandBus) it returns the matching Command Handler implementation instead of the Command Logging decorator. If I call Container.GetAllInstances, it returns both the implementation (first) and the decorator (second).

So, right now, the only way I am able to make this work is if I either explicitly choose the second item returned from Container.GetAllInstances or filter the results and choose the decorator using reflection. Here's an example:

public class CommandBus : ICommandBus
{
    public static IContainer Container;

    public void Execute(ICommand command)
    {
        var handlerType = typeof (ICommandHandler<>)
            .MakeGenericType(command.GetType());

        var handlers = Container
            .GetAllInstances(handlerType)
            .Cast<dynamic>();

        var handler = handlers.ToList()[1];

        handler.Execute((dynamic) command);
    }
}

However, this seems like a pretty ugly solution. There clearly must be something that I'm missing. First, why is Container.GetInstance returning the implementation rather than the decorator when I've explicitly added a decorator interception policy? Second, is there a better way that I should be doing this altogether?

Any ideas or suggestions would be greatly appreciated!

Matthew Renze
  • 634
  • 1
  • 6
  • 17
  • StructureMap 3 has [great support for decorators](https://stackoverflow.com/questions/30841303/define-filter-for-decorateallwith-method-in-structure-map-3). Why don't you use a decorator instead of an interceptor? It makes your code so much cleaner, more maintainable and it removes the need for your decorator to take a dependency on a third-party tool (the interception library in this case). – Steven Sep 22 '15 at 20:17
  • @Steven I assume it is just a misunderstanding of the terminology, but what I was attempting to do is interception via the dependency injection framework to wrap the command handler with a decorator. I was not, however, trying to do interception with an aspect-oriented programming framework. Hope this clears up any confusion. If not, I might need more information to understand what you are proposing. – Matthew Renze Sep 23 '15 at 21:38
  • Ah, I see the `CommandHandlerLoggerDecorator` now. In taht case, please carry on with what you're doing. – Steven Sep 24 '15 at 05:46

1 Answers1

4

See this remarkably similar sample (that I just wrote) in the StructureMap codebase for an example of using decorators with generic types: https://github.com/structuremap/structuremap/blob/b405d8f752b45ac250f057d9e3de8554f2a7f40f/src/StructureMap.Testing/Bugs/OpenGenericDecorator_question.cs

  • Your solution works perfectly Jeremy. Thanks for the quick response! : ) – Matthew Renze Sep 22 '15 at 18:37
  • In case anyone else uses Jeremy's solution, be sure you exclude the decorator in you scanning policy, so that you don't end up with duplicate decorators being returned by Container.GetAllInstances(), like so: `scan.Exclude(p => p == typeof (CommandHandlerLoggingDecorator<>));` – Matthew Renze Sep 22 '15 at 19:58