Search code examples
c#inversion-of-controlautofac

Autofac 6.2 doesn't (no longer) allow class with private constructor?


I have this code that used to work in Autofac 2.6, but now no longer works in 6.2 ( latest version):

class Program
{
    static void Main(string[] args)
    {
        Holder holder = null;

        Build(c =>
        {

            holder = new Holder() { Verifiers = c.Resolve<Verifiers>() };
        });
        var res = holder.Verifiers;
        Console.WriteLine("Success");
    }


    private static void Build(Action<IContainer> container)
    {
        var builder = new ContainerBuilder();
        builder.RegisterAssemblyTypes(typeof(Verifiers).Assembly).AsSelf().AsImplementedInterfaces();
        container(builder.Build());
    }
}

public class PrivateConstructorClass
{
    public static PrivateConstructorClass Create()
    {
        return new PrivateConstructorClass();
    }
    private PrivateConstructorClass() //this is the problem
    {

    }
}


public class Verifiers
{

}

public class Holder
{
    public Verifiers Verifiers { get; set; }
}

Due to this error:

Autofac.Core.Activators.Reflection.NoConstructorsFoundException
HResult=0x80131500 Message=No accessible constructors were found for the type 'AutofacTest46PrivateConstructor.PrivateConstructorClass'.
Source=Autofac StackTrace: at Autofac.Core.Activators.Reflection.DefaultConstructorFinder.GetDefaultPublicConstructors(Type type) at Autofac.Core.Activators.Reflection.DefaultConstructorFinder.FindConstructors(Type targetType) at Autofac.Core.Activators.Reflection.ReflectionActivator.ConfigurePipeline(IComponentRegistryServices componentRegistryServices, IResolvePipelineBuilder pipelineBuilder)
at Autofac.Core.Registration.ComponentRegistration.BuildResolvePipeline(IComponentRegistryServices registryServices, IResolvePipelineBuilder pipelineBuilder) at Autofac.Core.Registration.ComponentRegistration.BuildResolvePipeline(IComponentRegistryServices registryServices) at Autofac.Core.Registration.ComponentRegistryBuilder.Build() at Autofac.ContainerBuilder.Build(ContainerBuildOptions options) at AutofacTest46PrivateConstructor.Program.Build(Action`1 container) in D:.net Samples project\May 2021\AutofacTest46PrivateConstructor\Program.cs:line 30 at AutofacTest46PrivateConstructor.Program.Main(String[] args) in D:.net Samples project\May 2021\AutofacTest46PrivateConstructor\Program.cs:line 16

While I can "fix" the issue by making the the modifier of the constructor class from private to public, I still have questions here:

  1. Is this behavior documented somewhere, namely since when Autofac disallows private constructor whereas previously allowed?
  2. I would like to exclude class with only nonpublic constructor from being registered by Autofac, how to do it?

Solution

  • A lot has gone on since Autofac 2.6 was released eight years ago. One of those things is that we don't consider private constructors, as you have noticed. I'm sure it's in one of the release notes somewhere along the line, but we've moved from Google Code to GitHub, from Subversion to Git since then and some of the history has been lost. I can see it's been like this since at least 2015.

    The solution is to use your own IConstructorFinder implementation. Our default version is here so you can see what that would look like. You can then use the FindConstructorsWith extension to attach your constructor finder to the registration for your class.

    var finder = new MyCustomConstructorFinder();
    var builder = new ContainerBuilder();
    builder.RegisterType<MyType>().FindConstructorsWith(finder);