In this code:
container.Register<IDataHoldingSession<DbContext>, EntityFrameworkSession>();
container.RegisterAll<ISession>(typeof(IDataHoldingSession<DbContext>));
container.RegisterDecorator(typeof(IDataHoldingSession<>), typeof(ValidatingSession<>));
When the container is asked for IEnumerable<ISession>
, it is given a collection containing EntityFrameworkSession
, but the decorator is not applied. How can I make it apply the decorator in the above code?
I believe this occurs because the container is not asked for IEnumerable<IDataHoldingSession<T>>
. I interpret the XML documentation for RegisterAll
as implying that the container will be asked for an instance of IDataHoldingSession<DbContext>
in this case, which I figure should cause the decorator to be applied. However, it appears that the decorator is bypassed for this situation because RegisterAll
is called with the ISession
service type.
A registration in Simple Injector contains of two parts:
InstanceProducer
. This is the object produces instances and is responsible for interception and decorating instances. The InstanceProducer
doesn't know the TImplementation
of a registration, only the TService
.InstanceProducer
wraps an Registration
object. This object is responsible for building an Expression that creates the instance, does constructor injection, property injection, custom initialization, and it applies the lifestyle to the expression. The Registration
(only) knows about the TImplementation
.When you make a RegisterAll
registration, you supply types that reference other registrations that are made in the container. You are doing this by doing both Register<IDataHoldingSession<DbContext>>
and using that interface type in your RegisterAll
registration.
What RegisterAll
does under the covers, is querying the container for a registration of the given type (in your case IDataHoldingSession<DbContext>
). Since the requested type might be different from the service type of the collection (it usually does, and does in your case) the container grabs the Registration
from the found InstanceProducer
and it creates a new InstanceProducer
based on that Registration
with the actual service type of the collection. This looks as follows in the Simple Injector source code (in ContainerControlledCollection
):
return new InstanceProducer(typeof(TService), instanceProducer.Registration);
But since decorators are applied by the InstanceProducer
, we lose the decorator that you applied to IDataHoldingSession<T>
.
To be frank, I'm not sure why we implemented the behavior like this, since the most intuitive behavior would let the decorator for IDataHoldingSession<T>
still be applied. I think we tried to prevent having decorators being applied twice; this was a problem in earlier releases of Simple Injector.
I'll try to look into this and look if I can come up with a fix for v2.4, but I can only do this if I don't introduce a breaking change. In the meantime, I think the workaround you found yourself it very good. If I make the fix, I'll probably implement it internally much like you are doing now.
I'm sorry that Simple Injector isn't working the way you expected it to be.
UPDATE:
I just checked in a bug fix in the main branch that fixes this issue. The v2.4 release contains this fix.