Search code examples
c#dependency-injectiondecoratorioc-containersimple-injector

Register decorator conditional based on consumer service type in Simple Injector


I want to decorate IService in such a way that some consumers will a specific decorator based on their type, something like this:

container.Register<IService, Service>();
container.RegisterDecorator<IService, ServiceWithCaching>();
container.RegisterDecoratorConditional<IService, ServiceWithLogging>
  (ctx => ctx.Consumer.ServiceType == 
   typeof(IConsumerThatNeedsDecoratedService));
container.Register<IConsumerThatNeedsServiceWithLogging, Consumer1>();
container.Register<INormalConsumer, Consumer2>();

where both ServiceWithCaching and ServiceWithLogging take IService in their constructor, wrap an instance of IService, call it internally and do something else (e.g. caching, logging).

Both Consumer1 and Consumer2 accept IService in their constructor.

I want Consumer1 to be injected an instance of ServiceWithLogging and Consumer2 of ServiceWithCaching. The desired behvavior is that Consumer1 will use an instance of IService that caches the results, while Consumer2 will use an instance of IService that both caches results an logs calls.

Is it possible in Simple Injector and if not any known workarounds?


Solution

  • You can't do this with RegisterDecorator, but as the Applying decorators conditionally based on consumer section of the documentation explains, you can achieve this using RegisterConditional:

    container.RegisterConditional<IService, ServiceWithLogging>(
        c => c.Consumer.ImplementationType == typeof(Consumer1));
    
    container.RegisterConditional<IService, ServiceWithCaching>(
        c => c.Consumer.ImplementationType != typeof(Consumer1)
            && c.Consumer.ImplementationType != typeof(ServiceWithCaching));
    
    container.RegisterConditional<IService, Service>(c => !c.Handled);