Search code examples
c#autofacconstructor-injection

Using AutoFac constructor injection in a console application on different classes


So I have the idea that I'm missing something here, but I'm basically making a console application that will call multiple handlers.

Program.cs

private static IContainer _container;
static void Main(string[] args)
{
    _container = AutoFacBootstrapper.Init();
    var _backupFactory = _container.Resolve<IBackupFactory>();

    UserHandler.Init();
}

AutoFacBootstrapper.cs

public static IContainer Init()
{
    var builder = new ContainerBuilder();
    builder.RegisterType<BackupFactory>().As<IBackupFactory>();

    return builder.Build();
}

See all of this is nice and fun and I can use my factories in Program.cs, but when I try to use my factory in a different class (lets say UserHandler.cs), my _backupFactory will remain null (which makes sense).

UserHandler.cs

private static IBackupFactory _backupFactory;
public UserHandler(IBackupFactory backupFactory)
{
    _backupFactory = backupFactory;
}

public static void Init(string[] subCommands)
{
    var users = _backupFactory.GetFtpUsers();
}

How do I fix this, so I can use the constructor injection in another class, while only having to initialise it on startup?


Solution

  • The _backupFactory is null because the UserHandler constructor is never called.

    To solve this you would also need to create an interface for UserHandler and register the type in the AutoFacBootstrapper.

    interface IUserHandler
    {
        void PerformSomeAction();
    }
    
    class UserHandler : IUserHandler
    {
        private IBackupFactory _backupFactory;
        public UserHandler(IBackupFactory backupFactory)
        {
            _backupFactory = backupFactory;
        }
    
        public void PerformSomeAction()
        {
            var users = _backupFactory.GetFtpUsers();
        }
    }
    
    class AutoFacBootstrapper
    {
        public static IContainer Init()
        {
            var builder = new ContainerBuilder();
    
            builder.RegisterType<UserHandler>().As<IUserHandler>();
            builder.RegisterType<BackupFactory>().As<IBackupFactory>();
    
            return builder.Build();
        }
    }
    

    What is left, is for Autofac to resolve the IUserHandler type in the Main method.

        static void Main(string[] args)
        {
            IContainer container = AutoFacBootstrapper.Init();
    
            IUserHandler startPoint = container.Resolve<IUserHandler>();
            startPoint.PerformSomeAction();
        }
    

    As a side note, as the application is growing bigger and bigger and new projects will be created, registering all the types of the application in the AutoFacBootstrap class is not indicated.

    It will be better to have a separate class in each project that will inherit Autofac.Module which will have an override of the Load method. This way you will have access to the ContainerBuilder and be able to register all the desired types (from that assembly).

    Check out the Modules section from the Autofac documentation for more details