Search code examples
c#decoratorstructuremap3

Structuremap3 DecorateAllWith


I've been struggling getting DecorateAllWith working on generic interfaces. I've read some posts here where they solved it using interceptors but they seem to be using an older structure map version and it doesn't seem like a "clean" solution.

I would really need some help to get it working with structure map 3

I have a generic repository which i would like to decorate with both logging and caching

public interface IEntityRepository<T> where T : Entities.IEntity
{
}

I have about 20 interfaces that inherit IEntityRepository. Example mu UserRepository

public interface IUserEntityRepository : IEntityRepository<User>
{
}

And then I have the logging decorator concrete type which I would like all instances of IEntityRepository to be decorated with

public class LoggingEntityRepository<T> : IEntityRepository<T> where T : Entities.IEntity
{
    private readonly IEntityRepository<T> _repositoryDecorated;

    public LoggingEntityRepository(IEntityRepository<T> repositoryDecorated)
    {
        _repositoryDecorated = repositoryDecorated;
    }
}

Or are there other IoC containers better suited for what I am trying to accomplish?

Edit: Is there a way to decorate all interfaces that inherit from IEntityRepository


Solution

  • Here's a working example that answers your first question

    [Fact]
    public void DecorateAllWith_AppliedToGenericType_IsReturned()
    {
        var container = new Container(registry =>
        {
            registry.Scan(x =>
            {
                x.TheCallingAssembly();
                x.ConnectImplementationsToTypesClosing(typeof(IEntityRepository<>));
    
            });
    
            registry.For(typeof(IEntityRepository<>))
                .DecorateAllWith(typeof(LoggingEntityRepository<>));
        });
    
        var result = container.GetInstance<IEntityRepository<Entity1>>();
    
        Assert.IsType<LoggingEntityRepository<Entity1>>(result);
    }
    

    To answer your second question, I personally use (and contribute to) Simple Injector - it is one of the fastest containers available, has comprehensive support for generics and offers some powerful diagnostic services.

    The registrations in Simple Injector would look like this:

    [Fact]
    public void RegisterDecorator_AppliedToGenericType_IsReturned()
    {
        var container = new SimpleInjector.Container();
    
        container.RegisterManyForOpenGeneric(
            typeof(IEntityRepository<>), 
            typeof(IEntityRepository<>).Assembly);
    
        container.RegisterDecorator(
            typeof(IEntityRepository<>), 
            typeof(LoggingEntityRepository<>));
    
        var result = container.GetInstance<IEntityRepository<Entity1>>();
    
        Assert.IsType<LoggingEntityRepository<Entity1>>(result);
    }