2

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

Niclas
  • 217
  • 3
  • 9

1 Answers1

0

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);
}
qujck
  • 14,388
  • 4
  • 45
  • 74
  • Thanks for your answer. I managed to get that to work. However if I try to get an instance of IUserEntityRepository that wont work. Is there a way to accomplish that? Se my updated post – Niclas Aug 05 '14 at 11:12
  • `LoggingEntityRepository` does not implement `IUserEntityRepository` so cannot decorate it. You can only get it to work as-is if you refer to the service as `IEntityRepository` in your code. – qujck Aug 05 '14 at 11:22
  • Not even if IUserRepository inherits IEntityRepository? – Niclas Aug 05 '14 at 11:35
  • Nope. `IUserEntityRepository` is a `IEntityRepository` *but* `IEntityRepository` is **not** a `IUserEntityRepository` – qujck Aug 05 '14 at 11:45
  • OK, thanks. I was afraid that would be the case. Do you have any suggestions on another way to accomplish what I am trying to do? – Niclas Aug 05 '14 at 11:59
  • That's hard without knowing the details of each of the entity specific interfaces. Personally I would do away with them all and revert to using the generic interface. If you have anything specific you want to expose from a particular interface, say something like a `GetAllUsers()` method then you can do so with extensions methods `public static IEnumerable GetAllUsers(this IEntityRepository repository)` etc. – qujck Aug 05 '14 at 12:13
  • I understand. The entity specific interfaces has about 5 extra methods in them and the generic interface only has CRUD methods. I probably wouldn't like to use extension methods mainly because of the problems testing them and I also use mock implementations of the interfaces during development before moving to real database implementation in the end. – Niclas Aug 05 '14 at 12:33
  • Do you they all implement the same 5 methods? If so you could add them as abstract methods of an abstract base class. This sort of design is what makes the dynamic proxy interception seem attractive. My own preference is to use the Query pattern as described [here](http://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=92). One interface for all repositories and one interface for all queries makes decorating your objects a lot simpler :-) – qujck Aug 05 '14 at 13:02
  • I've had a look at the Query pattern and it works great with my decorators. Now I have both logging, caching and validation/permission decorators for my repositories. One last thing - in the current design there is a concrete Service layer fronting the repositories. I am pondering if the Query pattern should be applied to the respositores making the fronting service resposible for running the query and thus making the Query pattern "invisible" for the consumer. Or keep my old repositories as is and implement the Query pattern on the Service layer forcing consumers to construct queries. – Niclas Aug 07 '14 at 06:32
  • Again this is a presonal decision - I like to keep my repositories private to the data layer and only expose queries. You can make the code cleaner by having an extension method (normally with the same name `Handle`) to construct the query object and call the `Handle` method of the `QueryHandler` – qujck Aug 07 '14 at 08:44