Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to solve Autofac circular dependency?

Recently started using autofac and I hit a Circular dependency issue, which I had overcome while I was using Unity. Here is my code:

 void Main()
 {
    var builder = new ContainerBuilder();

    // 1) Every class needs logger
    // 2) Logger needs AppSettingsProvider which needs AppEnvironmentProvider
    // 3) Listener needs AppSettingsProvider which needs AppEnvironmentProvider

    builder.RegisterType<Logger>().As<ILogger>().SingleInstance();
    builder.RegisterType<AppSettingsProvider>().As<IAppSettingsProvider>().SingleInstance();
    builder.RegisterType<AppEnvironmentProvider>().As<IAppEnvironmentProvider>().SingleInstance();

    builder.RegisterType<Listener>().As<IListener>().SingleInstance();

    var container = builder.Build();

    var listener = container.Resolve<IListener>();
    listener.Do();

 }

 public interface IListener
 { 
    string Do();
 }

 public class Listener : IListener
 { 
    IAppSettingsProvider appSettingsProvider;
    public Listener(IAppSettingsProvider appSettingsProvider)
    {
        // this class needs IAppSettingsProvider to get some settings
        // but not actually used on this example.
        this.appSettingsProvider = appSettingsProvider;
    }
    public string Do()
    {
        return "doing something";
    }
 }

 public interface ILogger
 { 
    void Log(string message);
 }

 public class Logger : ILogger
 {
    IAppSettingsProvider appSettingsProvider;
    public Logger(IAppSettingsProvider appSettingsProvider)
    {
        this.appSettingsProvider = appSettingsProvider;
    }

    public void Log(string message)
    {
        // simplified
        if (this.appSettingsProvider.GetSettings())
        {
            Console.WriteLine(message);
        }
    }
 }

 public interface IAppSettingsProvider
 { 
    // will return a class, here simplified to bool
    bool GetSettings();
 }

 public class AppSettingsProvider : IAppSettingsProvider
 { 
    ILogger logger;
    public AppSettingsProvider(ILogger logger)
    {
        this.logger = logger;
    }

    public bool GetSettings()
    {
        this.logger.Log("Getting app settings");

        return true;
    }
 }


 public interface IAppEnvironmentProvider
 { 
    string GetEnvironment();
 }

 public class AppEnvironmentProvider : IAppEnvironmentProvider
 { 
    ILogger logger;
    public AppEnvironmentProvider(ILogger logger)
    {
        this.logger = logger;
    }
    public string GetEnvironment()
    {
        this.logger.Log("returning current environment");

        return "dev";
    }
 }

Any pointers on solving this will be helpful.

like image 600
Amit Avatar asked Dec 10 '22 11:12

Amit


1 Answers

You have 2 options here:

  1. Use Property Injection
  2. Use Factory (that might create a strong dependency with you factory)

Here is an example using Property Injection:

    static void Main()
    {
        var builder = new ContainerBuilder();

        // 1) Every class needs logger
        // 2) Logger needs AppSettingsProvider which needs AppEnvironmentProvider
        // 3) Listener needs AppSettingsProvider which needs AppEnvironmentProvider

        builder.RegisterType<Logger>().As<ILogger>().SingleInstance();

        builder.RegisterType<AppSettingsProvider>()
            .As<IAppSettingsProvider>()
            .SingleInstance()
            .PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies);

        builder.RegisterType<AppEnvironmentProvider>().As<IAppEnvironmentProvider>().SingleInstance();

        builder.RegisterType<Listener>().As<IListener>().SingleInstance();

        var container = builder.Build();

        var listener = container.Resolve<IListener>();

        Console.WriteLine(listener.Do());

        Console.Read();

    }

    public interface IListener
    {
        string Do();
    }

    public class Listener : IListener
    {
        IAppSettingsProvider appSettingsProvider;
        public Listener(IAppSettingsProvider appSettingsProvider)
        {
            // this class needs IAppSettingsProvider to get some settings
            // but not actually used on this example.
            this.appSettingsProvider = appSettingsProvider;
        }
        public string Do()
        {
            return "doing something using circular Dependency";
        }
    }

    public interface ILogger
    {
        void Log(string message);
    }

    public class Logger : ILogger
    {
        IAppSettingsProvider appSettingsProvider;
        public Logger(IAppSettingsProvider appSettingsProvider)
        {
            this.appSettingsProvider = appSettingsProvider;
        }

        public void Log(string message)
        {
            // simplified
            if (this.appSettingsProvider.GetSettings())
            {
                Console.WriteLine(message);
            }
        }
    }

    public interface IAppSettingsProvider
    {
        // will return a class, here simplified to bool
        bool GetSettings();
    }

    public class AppSettingsProvider : IAppSettingsProvider
    {
        ILogger logger;
        public AppSettingsProvider()
        {

        }

        public ILogger Logger { get; set; }

        public bool GetSettings()
        {
            Logger.Log("Getting app settings");

            return true;
        }
    }


    public interface IAppEnvironmentProvider
    {
        string GetEnvironment();
    }

    public class AppEnvironmentProvider : IAppEnvironmentProvider
    {
        ILogger logger;
        public AppEnvironmentProvider(ILogger logger)
        {
            this.logger = logger;
        }
        public string GetEnvironment()
        {
            this.logger.Log("returning current environment");

            return "dev";
        }
    }

Here is Autofac suggestion: Autofac reference

like image 102
Rick Avatar answered Dec 31 '22 03:12

Rick