public MessageSender(AzureServiceBusSettings serviceBusSettings,
                             ServiceBusConnection serviceBusConnection,
                             NamespaceInfo namespaceInfo,
                             MessageProcessingContext context,
                             string destinationQueue)
        {
            _messageProcessingContext = context;
            _settings      = serviceBusSettings;
            _namespaceInfo = namespaceInfo;

            // The default retry policy passed in to the sender provides an exponential backoff for transient failures.
            if (context == null)
            {
                _messageSender = new Microsoft.Azure.ServiceBus.Core.MessageSender(serviceBusConnection, destinationQueue, RetryPolicy.Default);
            }
            else
            {
                var viaQueue = context.GetMessageReceiver().Path;
                if (viaQueue == destinationQueue)
                {
                    _messageSender = new Microsoft.Azure.ServiceBus.Core.MessageSender(serviceBusConnection, destinationQueue, RetryPolicy.Default);
                }
                else
                {
                    _messageSender = new Microsoft.Azure.ServiceBus.Core.MessageSender(serviceBusConnection, destinationQueue, viaQueue, RetryPolicy.Default);
                }
            }
        }
        public async Task RunTest()
        {
            var senderCxn = new ServiceBusConnectionStringBuilder(targetNamespaceConnectionString)
            {
                EntityPath = targetQueue
            };
            var sendSideClient = new Microsoft.Azure.ServiceBus.Core.MessageSender(senderCxn);

            var receiverCxn = new ServiceBusConnectionStringBuilder(sourceNamespaceConnectionString)
            {
                EntityPath = sourceQueue
            };
            var receiveSideClient = new Microsoft.Azure.ServiceBus.Core.MessageReceiver(receiverCxn);

            var start = DateTime.UtcNow;

            var sw = new Stopwatch();

            sw.Start();
            var tracker = new ConcurrentDictionary <string, long>();

            Console.WriteLine("sending");
            List <Task> sendTasks = new List <Task>();

            for (int j = 0; j < 1000; j++)
            {
                string msgid = Guid.NewGuid().ToString();
                tracker[msgid] = sw.ElapsedTicks;
                var message = new Message(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 });
                message.MessageId = msgid;
                sendTasks.Add(sendSideClient.SendAsync(message));
            }

            await Task.WhenAll(sendTasks);

            ConcurrentBag <long> durations = new ConcurrentBag <long>();

            Console.Write("receiving: ");
            var receiveTask = Task.Run(async() =>
            {
                while (!tracker.IsEmpty)
                {
                    var message = await receiveSideClient.ReceiveAsync(100, TimeSpan.FromSeconds(30));
                    if (message != null)
                    {
                        foreach (var msg in message)
                        {
                            string msgid = msg.MessageId;
                            if (tracker.TryRemove(msgid, out var swval))
                            {
                                durations.Add(sw.ElapsedTicks - swval);
                            }
                            await receiveSideClient.CompleteAsync(msg.SystemProperties.LockToken);
                        }
                    }
                    else
                    {
                        break;
                    }
                }
            });

            await receiveTask;

            Console.WriteLine();
            Assert.True(tracker.IsEmpty, $"tracker is not empty: {tracker.Count}");

            Console.WriteLine(((double)durations.Sum() / (double)durations.Count) / TimeSpan.TicksPerMillisecond);
        }