Send Event To Multiple Topics Using ServiceBusClient/ServiceBusSender

I come across a situation where an application has to send an event to 2 different Queues or Topics for a business need. We often make mistakes in the way of establishing connection to SB which leads to performance issues. I am going to explain how it can be made better irrespective of multiple topics or queues.

Azure.Messaging.ServiceBus is the latest Microsoft SDK used to send messages.

ServiceBusClient and ServiceBusSender are 2 client objects responsible for sending events to Queue or Topic. 

Establishing a connection is an expensive operation that you can avoid by reusing the same client objects for multiple operations. If we close these 2 objects, it will tear down the connection to service bus. 

So It is advisable to create Singleton objects for both of them and inject it.

We have to create Servicebus sender objects for each topic or queue of our interest and add it to a dictionary that has a Name associated to it. This dictionary will be added as singleton in the startup. Code Snippet below,

services.AddSingleton((serviceBusSenders) => {
    var sbSenders = new Dictionary < string,
        ServiceBusSender > ();
    var client = new ServiceBusClient("Topic1ConnectionString", new ServiceBusClientOptions() {
        TransportType = ServiceBusTransportType.AmqpWebSockets
    });
    sbSenders.Add("Topic1", client.CreateSender("Topic1Name"));
    var nightlyRunClient = new ServiceBusClient("Topic2ConnectionString", new ServiceBusClientOptions() {
        TransportType = ServiceBusTransportType.AmqpWebSockets
    });
    sbSenders.Add("Topic2", nightlyRunClient.CreateSender("Topic2Name"));
    return sbSenders;
});

Now this Dictionary can be injected anywhere in the application and the corresponding ServiceBusSender can be retrieved by using the key/name associated to it. Below is a helper class that can be used from any other method.

public class Util {
    private readonly Dictionary < string, ServiceBusSender > _serviceBusSenders;
    public Util(Dictionary < string, ServiceBusSender > serviceBusSenders) {
        _serviceBusSenders = serviceBusSenders;
    }
    public async Task SendServiceBusEvent(dynamic messageBody, string topic) {
        string message = JsonConvert.SerializeObject(messageBody);
        await _serviceBusSenders[topic].SendMessageAsync(new ServiceBusMessage(message));
    }
}

Now we can add any new topic to the dictionary and consume it from here using the name associated to it.