Suppose I have a component that implements multiple interfaces:
public interface IService1 { }
public interface IService2 { }
public interface IService3 { }
public interface ICommonService : IService1, IService2, IService3 { }
public class CoreComponent : ICommonService { }
and its decorator
public class DecoratorComponent : ICommonService
{
public DecoratorComponent(ICommonService coreComponent) { }
}
And then I need to resolve instances of IService1-3
and ICommonService
as well.
That's the problem.
Because I'd like to have a single instance of my CoreComponent
and a single instance of the decorator. But after reading this issue I understood that this is impossible (as far as I understood).
At least, I want to have a single instance of my CoreComponent
and multiple decorator instances, as many as the services, decorating that single core component instance.
But when I registered them as following
builder
.RegisterType<CoreComponent>()
.As<ICommonService>()
.As<IService1>()
.As<IService2>()
.As<IService3>()
.SingleInstance();
builder.RegisterDecorator<DecoratorComponent, ICommonService>();
builder.RegisterDecorator<DecoratorComponent, IService1>();
builder.RegisterDecorator<DecoratorComponent, IService2>();
builder.RegisterDecorator<DecoratorComponent, IService3>();
and resolve IService1
, I've got an instance of the decorator, decorating an instance of the decorator, decorating an instance of the core component. That's frustrating.
How to register that decorator properly to have only one level of decorators in my case, and have all the services resolved?
UPD: here is the sample code with my registration and the registration in the accepted answer: https://dotnetfiddle.net/PxjRqf
You can see that strange Autofac behavior when registering as above and how to fix that.
Instead of register the CoreComponent
exposed as IService1
, IService2
and IService3
, you could register it only exposed as ICommonService
and add registrations for the other interfaces forwarding them to an ICommonService
resolution.
var builder = new ContainerBuilder();
// Register the type as singleton
builder
.RegisterType<CoreComponent>()
.As<ICommonService>()
.SingleInstance();
// Register the decorator only once, for ICommonService.
builder
.RegisterDecorator<DecoratorComponent, ICommonService>();
// Now, forward service resolution to ICommonService
builder
.Register(container => container.Resolve<ICommonService>())
.As<IService1>()
.As<IService2>()
.As<IService3>();
In the end, no matter what interface you resolve a CoreComponent
from (either ICommonService
or any IServiceX
), Autofac will always end up resolving it from the ICommonService
registration, which is decorated by the DecoratorComponent
.
Hope that helps.