user14626381
user14626381

Reputation:

Make Autofac resolve non-public constructors

I´m using Autofac in my WPF application for dependency injection and can´t resolve this problem.

I have created this abstract class ListItemViewModelBase from which two classes PasswordItemViewModel and CardItemViewModel inherits.

ListItemViewModelBase.cs


    public abstract class ListItemViewModelBase
    {
        protected readonly IMessenger _messenger;
    
        public string Id { get; }
        public string Name { get; }
        public string Notes { get; }
    
        protected ListItemViewModelBase(IMessenger messenger, string id, string name, string notes)
        {
            _messenger = messenger;
    
            Id = id;
            Name = name;
            Notes = notes;
        }
    
        public abstract void SeeDetails();
    }

PasswordItemViewModel.cs


    public partial class PasswordItemViewModel : ListItemViewModelBase
    {
        public string UserName { get; }
        public string Password { get; }
        public string Website { get; }
    
        public PasswordItemViewModel(IMessenger messenger, string id, string name, string userName, string password, string website, string notes) : base(messenger, id, name, notes)
        {
            UserName = userName;
            Password = password;
            Website = website;
        }
    
        [RelayCommand]
        public override void SeeDetails()
        {
            _messenger.Send(new PasswordDetailMessage(this));
        }
    }

CardItemViewModel.cs


    public partial class CardItemViewModel : ListItemViewModelBase
    {    
        public string CardNumber { get; }
        public int ExpMonth { get; }
        public int ExpYear { get; }
    
        public CardItemViewModel(IMessenger messenger, string id, string name, string cardNumber, int expMonth, int expYear, string notes) : base(messenger, id, name, notes)
        {
            CardNumber = cardNumber;
            ExpMonth = expMonth;
            ExpYear = expYear;
        }
    
        [RelayCommand]
        public override void SeeDetails()
        {
            _messenger.Send(new CardDetailMessage(this));
        }
    }

My App.xaml.cs where the Autofac is configured looks like this:

App.xaml.cs


    public partial class App : Application
        {
            public static IServiceProvider ServiceProvider { get; private set; }
    
            [STAThread]
            public static void Main(string[] args)
            {
                using IHost host = CreateHostBuilder(args).Build();
    
                CreateGenericHost(host);
                InitAppAndRun();
            }
    
            private static void InitAppAndRun()
            {
                var app = new App();
                app.InitializeComponent();
                app.MainWindow = ServiceProvider.GetRequiredService();
                app.MainWindow!.Visibility = Visibility.Visible;
                app.Run();
            }
    
            #region Host builder
    
            private static IHostBuilder CreateHostBuilder(string[] args)
            {
                return Host.CreateDefaultBuilder(args)
                    .UseServiceProviderFactory(new AutofacServiceProviderFactory())
                    .ConfigureServices(ConfigureServices)
                    .ConfigureContainer(ConfigureAutofacBuilder);
            }
    
            private static void ConfigureAutofacBuilder(HostBuilderContext ctx, ContainerBuilder builder)
            {
                builder.RegisterModule>();
                builder.RegisterModule>();
    
                var config = new ConfigurationBuilder();
                config.AddJsonFile("autofac.json");
    
                var module = new ConfigurationModule(config.Build());
                builder.RegisterModule(module);
            }
    
            private static void CreateGenericHost(IHost host)
            {
                host.Start();
                ServiceProvider = host.Services;
            }
    
            private static void ConfigureServices(HostBuilderContext ctx, IServiceCollection services)
            {
                services.AddSingleton();
            }
            #endregion
        }

When I try to start the application, program fails on using IHost host = CreateHostBuilder(args).Build(); and throws this error message:

Autofac.Core.Activators.Reflection.NoConstructorsFoundException: 'No accessible constructors were found for the type 'TestApp.Bases.ListItemViewModelBase'.'

Seems like Autofac can´t resolve non-public constructor of ListItemViewModelBase class. Is there a way to make Autofac resolve these type of non-public constructors?

Thanks, Tobias

Response to reply from Orenico:

Here is autofac.json which contains basically nothing.


    {
      "modules": [],
      "components": []
    }

Upvotes: 0

Views: 287

Answers (1)

Travis Illig
Travis Illig

Reputation: 23894

There are some typos in the sample code, like builder.RegisterModule>(), which won't compile and indicates there are registrations and other stuff going on that you're not showing us.

However:

You can't directly instantiate an abstract class. Like, you can't do new ListItemViewModelBase. That means you can't register it. You can register derived classes As it, but even if Autofac could find the constructor you'd still hit a brick wall because it's not a concrete class.

If Autofac is resolving a type by reflection it doesn't go all the way down the chain looking at constructors, it only looks at the thing you're resolving. That's why it sounds like you probably tried to register that abstract class.

If I had to guess, you have some assembly scanning registrations in those modules you're not showing us where you try registering all the view models and you didn't exclude the base class from the registrations.

Upvotes: 1

Related Questions