Home > Software design >  Constructor Injection Only When Needed
Constructor Injection Only When Needed

Time:07-06

I am looking for a way to inject an interface into a class only when it needs to be used.

For context I am trying to set up publish/subscribe messaging between two different projects, and to do this I am using both RabbitMQ and Azure Service Bus to suit different needs. To determine which one I want to use I use a boolean value which is set in app settings, like so:

if (AppSettingsProvider.MessagingEnabled)
{
    if (AppSettingsProvider.AzureServiceBusEnabled)
    {
        services.AddSingleton<IEventBus, EventBusServiceBus>(
        sp =>
        {
            var serviceBusPersistentConnection = sp.GetRequiredService<IServiceBusPersistentConnection>();
            var scope = sp.CreateScope();
            var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>();
            var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionManager>();
            var subscriptionClientName = AppSettingsProvider.SubscriptionName;

            return new EventBusServiceBus(serviceBusPersistentConnection, logger, eventBusSubcriptionsManager, subscriptionClientName, scope);
        });
    }
    else
    {
        services.AddSingleton<IEventBus, EventBusRabbitMQ>(
        ...
    }
}

I have an if statement that wraps all of this checking MessagingEnabled. Ideally I don't want either implementation to be set up if messaging is turned off.

My issue here is that IEventBus is injected in different event publishing classes, however if I have messaging turned off I get exceptions that there is no instantiation of the injected IEventBus. As an example:

public class EventBusPublisher : IEventBusPublisher
{
    private readonly IEventBus _eventBus;
    private readonly IMapper _mapper;

    public EventBusPublisher(IMapper mapper, IEventBus eventBus)
    {
        _mapper = mapper;
        _eventBus = eventBus;
    }

I thought maybe if I made the IEventBus nullable it may solve this issue however it has not.

This class will never be used if messaging is turned off, so there should be no problems with there not being an event bus implementation available in this case. Is there a way to, I guess tell the class its okay that there is no implementation for it?

Thanks.

CodePudding user response:

It's common practice to provide a null implementation that does nothing, a common example being the NullLogger.

You can register that implementation for IEventBus, if messaging is disabled.

Depending on your use case, the class could either just do nothing, if methods are called, or possibly throw an InvalidOperationException.

Of course, it would technically be possible to register null like this:

services.AddSingleton<IEventBus>(factory => null);

But I would strongly advise against that, because now you would have to check your dependency for null everywhere and kind of defeats the purpose of DI.

  • Related