ServiceBus QueueClient and TopicClient object resue I'm writing an Azure function using Visual Studio (multi-layers project), where I'm managing all Azure ServiceBus related code in one class.

(follow-up)

public class MessageBroker : IMessageBroker, IDisposable
{
    private readonly IAppConfiguration appConfiguration;
    private TopicClient topicClient;
    private QueueClient queueClient;

    public MessageBroker(IAppConfiguration appConfiguration)
    {
        this.appConfiguration = appConfiguration;
    }

    public async Task SendMessageToQueueAsync(string queueName, string message)
    {
        this.queueClient = QueueClient.CreateFromConnectionString(appConfiguration.BrokerConnectionString, queueName);
        BrokeredMessage brokeredMessage = new BrokeredMessage(message);
        await queueClient.SendAsync(brokeredMessage);
    }

    public async Task SendMessageToTopicAsync(string topicName, string message)
    {
        this.topicClient = TopicClient.CreateFromConnectionString(appConfiguration.BrokerConnectionString, topicName);
        BrokeredMessage brokeredMessage = new BrokeredMessage(message);
        await topicClient.SendAsync(brokeredMessage);
    }

    public void Dispose()
    {
        this.queueClient.Close();
        this.topicClient.Close();
    }
}


I use the [Inject] attribute to use DI in the Azure function. Whenever I need to send any message into a queue or topic, I inject IMessageBroker and call thr SendMessageToQueueAsync method. I see a Microsoft recommendation here to reuse QueueClient and TopicClient.

IMessageBroker is Singleton in my DI configuration.

Will the QueueClient.CreateFromConnectionString method create a new object every time or reuse a connection internally based on the same ConnectionString or queuename?

Is there anything I can do better on this code?
Having topicClient and queueClient as class fields is unnecessary here, and potentially leads to exception scenarios.

For example, if you were to create a new MessageBroker and immediately call Dispose() without first calling both the other methods then a NullReferenceException will be thrown as topicClient and queueClient are only defined within these methods.

An alternative could be to make use of the using syntax to instantiate a client and dispose of it when done. e.g.

using(var topicClient = TopicClient.CreateFromConnectionString(appConfiguration.BrokerConnectionString, topicName))
{
    BrokeredMessage brokeredMessage = new BrokeredMessage(message);
    await topicClient.SendAsync(brokeredMessage);
}


Using this approach would allow you to remove the IDisposable implementation.

If you want to be able to re-use the same topicClient and queueClient then you could have a MessageBroker for a specific queueName and/or topicName, and define the clients from the constructor.
(Creating new MessageBrokers as necessary for new queue and topic names.)

public class MessageBroker : IMessageBroker, IDisposable
{
    private readonly TopicClient topicClient;
    private readonly QueueClient queueClient;

    public MessageBroker(IAppConfiguration appConfiguration, string queueName, string topicName)
    {
        this.queueClient = QueueClient.CreateFromConnectionString(appConfiguration.BrokerConnectionString, queueName);
        this.topicClient = TopicClient.CreateFromConnectionString(appConfiguration.BrokerConnectionString, topicName);
    }

    public async Task SendMessageToQueueAsync(string message)
    {
        BrokeredMessage brokeredMessage = new BrokeredMessage(message);
        await queueClient.SendAsync(brokeredMessage);
    }

    public async Task SendMessageToTopicAsync(string message)
    {
        BrokeredMessage brokeredMessage = new BrokeredMessage(message);
        await topicClient.SendAsync(brokeredMessage);
    }

    public void Dispose()
    {
        this.queueClient.Close();
        this.topicClient.Close();
    }
}


If you have need of only one MessageBroker (i.e. one topicName and queueName) then this will be sufficient, and an instance of this can be registered within your DI.

Otherwise, you will need some sort of MessageBrokerFactory which can be used to create a MessageBroker for a given queue/topic name, that can then be re-used.

public MessageBrokerFactory {
    private readonly IAppConfiguration appConfiguration;

    public MessageBrokerFactory(IAppConfiguration appConfiguration)
    {
        this.appConfiguration = appConfiguration;
    }

    public IMessageBroker Create(string queueName, string topicName)
    {
        return new MessageBroker(
            this.appConfiguration,
            queueName,
            topicName);
    }
}