I ran in to some unexpected behaviour in Autofac (v4.4.0, .NET 4.6.1), which I feel may be a bug.
From the documentation:
Default Registrations
If more than one component exposes the same service, Autofac will use the last registered component as the default provider of that service:
e.g. If I do this:
builder.RegisterType<FooOne>().As<IFoo>();
// Next line replaces default IFoo implementation
builder.RegisterType<FooTwo>().As<IFoo>();
I expect (and get) an instance of FooTwo
when I resolve IFoo
from the container.
However, if I have already registered an IFoo
, and I use the RegisterDecorator<T>
function to register a decorator of IFoo
, it does not replace the default registration of IFoo
. e.g:
// Register FooOne directly
builder.RegisterType<FooOne>().As<IFoo>(); // (1)
// Now set up a decorator
builder.RegisterType<FooOne>().Named<IFoo>("foo");
builder.RegisterDecorator<IFoo>((c, inner) =>
new DecoratorFoo(inner), fromKey: "foo");
Will resolve IFoo
as an undecorated FooOne
. This feels inconsistent to me; a violation of the principle of least astonishment.
You might claim that I shouldn't have line (1) at all (and the code works correctly without it) - but it's an accepted idiom (e.g. here) to use a plug-in to replace registrations.
In my case, this bug manisfested in a fairly large codebase where the wrapped type was already registered by a convention and, now needing to be decorated, requires a significant re-think of how registration is done.
A Gist suitable for LINQPad demonstrating the issue is here.
Is there any design reason for the observed behaviour that I am missing? Is there a way to have the decorator registration replace the default?