Autofac – None of the constructors found can be invoked

The bug

A common pattern used when working with Autofac (or any other IoC containers) is to register multiple implementations of an interface, then resolve them all and call a method on each implementation (e.g.: an IEventHandler interface that you use notify all registered handlers that something happened).

Take the following example:

Trying to resolve all implementors of IHaveDeferredEnumerable via .Resolve<IEnumerable<IHaveDeferredEnumerable>>() will throw

None of the constructors found with ‘Autofac.Core.Activators.Reflection.DefaultConstructorFinder’ on type ‘Autofac.Test.Scenarios.ScannedAssembly.HasDeferredEnumerable+<Get>d__0’ can be invoked with the available services and parameters:
Cannot resolve parameter ‘Int32 <>1__state’ of constructor ‘Void .ctor(Int32)’.

However, trying to resolve a single implementation of the interface via .Resolve<IHaveDeferredEnumerable>() will work as expected. This means that HasDeferredEnumerable can be built independently, however for some reasons it cannot be constructed when trying to get all implementations of IHaveDeferredEnumerable.

The journey

Studying the error message further reveals some strange behavior, Autofac is complaining that the type 'Autofac.Test.Scenarios.ScannedAssembly.HasDeferredEnumerable+<Get>d__0' cannot be resolved because of some 'Int32 <>1__state' parameter required in a 'Void .ctor(Int32)' constructor. Totally weird, as I am indirectly asking for the type 'Autofac.Test.Scenarios.ScannedAssembly.HasDeferredEnumerable' which only has the default parameter-less constructor, weird.

To be studied and understood, a problem must be first isolated, therefore, I stripped all other code doing container work and was only left with IHaveDeferredEnumerableHasDeferredEnumerable, and the container registration cb.RegisterAssemblyTypes(ScenarioAssembly).AsImplementedInterfaces();

To get even better isolation, I changed the container registration from registering all the types found in my test assembly (RegisterAssemblyTypes) with cb.RegisterType<HasDeferredEnumerable>().As<IHaveDeferredEnumerable>(). Now everything worked as expected, I was able to get the single implementation via .Resolve<IHaveDeferredEnumerable>() and all implementations via .Resolve<IEnumerable<IHaveDeferredEnumerable>>(). It was now obvious that the problem occurred sometime during type registration and only when bulk registering types via the RegisterAssemblyTypes method.

Since Autofac is an open source project I checked out the repository, wrote a failing test and step-by-step debugged my way through the type registration process. This is how I found out that a concrete implementation was discovered for IEnumerable<IHaveDeferredEnumerable>, even though there is none in my scanned assembly.

Since this voodoo magic needs to be cleared out, I fired up dotPeek and decompiled my assembly, to find the following:

My HasDeferredEnumerable class has been enriched with a private class, which implements IEnumerable<IHaveDeferredEnumerable> and not surprisingly requires an integer to be constructed. How did that class ended-up in there without me typing it you ask? Well, the .NET compiler does in fact changes your code and generates new types as needed. In this particular case, it was because of the deferred execution in the Get() method – the compiler generates a helper state machine class to handle your deferred execution.

The fix

Fixing the issue was fairly trivial as the helper class is decorated with the [CompilerGenerated] attribute and it was just a matter of filtering out these compiler generated classes when running bulk type discovery. You can find the accepted pull request here and it will probably only end-up in version 4.0.0.

If you cannot wait until version 4.0.0 you can either remove the deferred execution (remove yield return/break) from the classes affected by the bug, or just make sure to manually register them into the container.

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>