Dependency Injection With Autofac C# - Is It Possible To Specify A Factory Method When Registering A Generic Type

662 views Asked by At

I am very new to DI and Autofac. I have a singleton class ProducerService, as listed below. This is used as a dependency in the constructor of a BackgroundService. The ProducerService has a constructor injected dependency, IKafkaProducerAggregate, also listed below.

How can I create a single instance of IKafkaProducerAggregate<TKey, Tvalue> that gets created for injection into the ProducerService<TKey, TValue>? This contains an instance of IProducer from the external Kafka confluent dotnet library, via a factory method IProducer<TKey, TValue> producer = new ProducerBuilder<TKey, TValue>(Config.Producer).Build();. Can I use some sort of factory method with Autofac that creates the aggregate instance and initialise IProducer using Kafka confluences factory method?

So far, I have an Autofac Module that registers the producer service and am struggling to understand how to use something similar to a factory method??? that would create an IKafkaProducerAggregate when the ProducerService is created :

Assembly serializers = typeof(ConsumerService).GetTypeInfo().Assembly;

builder.RegisterGeneric(typeof(ProducerService<,>))
    .As(typeof(IKafkaProducer<,>))
    .SingleInstance();

Interface: IKafkaProducerAggregate

public interface IKafkaProducerAggregate<TKey, TValue>
{
    IProducer<TKey, TValue> Producer { get; }
    Action<DeliveryReport<TKey, TValue>> DeliveryReportAction { get; }
}

Class: ProducerService

namespace WebApp.Kafka
{
    public class ProducerService<Key, Value> : IProducerService<Key, Value>, IDisposable
    {
        private bool Disposed { get; set; }
        private IKafkaProducerAggregate<Key, Value> ProducerAggregate { get; }
        private ILogger Logger { get; set; }


        ProducerService(
            IKafkaProducerAggregate<Key, Value> aggregate,
            ILogger<ProducerService<Key, Value>> logger)
        {
            Logger = logger ?? throw new ArgumentNullException(nameof(logger));
            ProducerAggregate = aggregate ?? throw new ArgumentNullException(nameof(aggregate));

            Disposed = false;

            Logger.LogInformation("ProducerService constructor called");
        }

        public void Produce(string topic, Key key, Value value)
        {
            ProducerAggregate.Producer.Produce(topic, new Message<Key, Value> { Key = key, Value = value }, ProducerAggregate.DeliveryReportAction);

            Logger.LogInformation("Produce topic : {}, key : {}, value : {}", topic, key.ToString(), value.ToString());
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!Disposed)
            {
                if (disposing)
                {
                    Logger.LogInformation("Disposing Kafka producer...");
                    ProducerAggregate.Producer.Dispose();
                }

                Disposed = true;
            }
        }

        ~ProducerService()
        {
            Dispose(false);
        }
    }
}
1

There are 1 answers

2
Paolo Costa On

You don't need any factory to have a new instance of a dependency to be created in the constructor, you simply have to use the InstancePerDependency lifetime scope, and not the SingleInstance.

https://autofaccn.readthedocs.io/en/latest/lifetime/instance-scope.html