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);
        }
        public async Task Send <T>(T message, string messageId = null, Guid?tenantId = null, DateTime?scheduleAt = null)
        {
            // serialize
            var serializedMessage = JsonConvert.SerializeObject(message);
            var messageBytes      = Encoding.UTF8.GetBytes(serializedMessage);

            var effectiveMessageId = messageId;

            if (string.IsNullOrEmpty(effectiveMessageId))
            {
                effectiveMessageId = Guid.NewGuid().ToString();
            }

            string messageUri = null;
            // Check the length of the serialized message body, if it is too long, upload it
            // to blob storage. Subtract 64kb from the max size to allow room for the message header,
            // which is also included in the message size.
            var skuMaxMessageSizeKb = _namespaceInfo.MessagingSku == MessagingSku.Premium ? 1024 : 256;

            if (messageBytes.Length > (skuMaxMessageSizeKb - 64) * 1024)
            {
                messageUri = await UploadMessageBodyToBlob(effectiveMessageId, messageBytes).ConfigureAwait(false);
            }

            Message brokerMessage = null;

            if (messageUri == null)
            {
                brokerMessage = new Message(messageBytes);
            }
            else
            {
                brokerMessage = new Message();
                brokerMessage.UserProperties.Add(Constants.HeaderKeys.RPBlobSizeBytes, messageBytes.Length);
            }

            brokerMessage.MessageId = effectiveMessageId;

            // Set the type so it can be deserialized on receive
            brokerMessage.UserProperties.Add(Constants.HeaderKeys.RPMessageType, message.GetType().AssemblyQualifiedName);

            // set the delivery time if it was specified
            if (scheduleAt != null)
            {
                brokerMessage.ScheduledEnqueueTimeUtc = scheduleAt.Value;
            }

            // set the partition key if present in order to make transactions work
            if (_messageProcessingContext != null)
            {
                var innerContext   = _messageProcessingContext as MessageProcessingContext;
                var contextMessage = innerContext.GetMessage();
                brokerMessage.ViaPartitionKey = contextMessage.PartitionKey;
            }

            if (!string.IsNullOrEmpty(_settings.ContextId))
            {
                brokerMessage.UserProperties.Add(Constants.HeaderKeys.RPContextId, _settings.ContextId);
            }

            if (tenantId.HasValue)
            {
                brokerMessage.UserProperties.Add(Constants.HeaderKeys.RPTenantId, tenantId.Value);
            }
            // send
            // Send exceptions are handled internally by the _messageSender with a retry policy.
            // exceptions that fail all stages of the retry policy will be thrown out.
            await _messageSender.SendAsync(brokerMessage).ConfigureAwait(false);
        }