public Task StartAsync(CancellationToken cancellationToken)
        {
            // Create a channel for this reader
            _channel = _connection.CreateChannel();

            // Create a consumer for the queue. This is a method implemented by RabbitMQ.Client to easily subscribe to incoming messages on this queue
            var consumer = new EventingBasicConsumer(_channel);

            // Add an event handler for receiving messages on the queue
            consumer.Received += (evt, evt2) =>
            {
                if (HandleMessage(evt2))
                {
                    // Acknowledge this message as handled
                    _channel.BasicAck(evt2.DeliveryTag, false);
                }
                else
                {
                    // Reject the message and put it back on the queue for trying again.
                    _channel.BasicReject(evt2.DeliveryTag, true);
                }
            };

            // On the provided queue name, register our consumer as a consumer.
            _channel.BasicConsume(_queueName.Name, false, consumer);

            return(Task.CompletedTask);
        }
        public Task PublishMessageAsync <T>(string exchange, string routingKey, string messageType, T value)
        {
            using var channel = _connection.CreateChannel();

            var basicProperties = channel.CreateBasicProperties();

            basicProperties.ContentType  = "application/json";
            basicProperties.DeliveryMode = 2;
            // Add a MessageType header, this part is crucial for our solution because it is our way of distinguishing messages
            basicProperties.Headers = new Dictionary <string, object> {
                ["MessageType"] = messageType
            };

            var body = JsonSerializer.SerializeToUtf8Bytes(value);

            // Publish this without a routing key to the RabbitMQ broker
            channel.BasicPublish(exchange, routingKey, true, basicProperties, body);

            return(Task.CompletedTask);
        }