public async Task TransactionalSendViaCommitTest() { var connection = new ServiceBusConnection(ConnectionString); var intermediateQueue = default(ServiceBusScope.QueueScope); var destination1 = default(ServiceBusScope.TopicScope); var destination2 = default(ServiceBusScope.QueueScope); var intermediateSender = default(MessageSender); var intermediateReceiver = default(MessageReceiver); var destination1Sender = default(MessageSender); var destination1ViaSender = default(MessageSender); var destination2ViaSender = default(MessageSender); var destination1Receiver = default(MessageReceiver); var destination2Receiver = default(MessageReceiver); try { intermediateQueue = await ServiceBusScope.CreateQueueAsync(partitioned : true, sessionEnabled : false); destination1 = await ServiceBusScope.CreateTopicAsync(partitioned : true, sessionEnabled : false); destination2 = await ServiceBusScope.CreateQueueAsync(partitioned : false, sessionEnabled : false); var intermediateQueueName = intermediateQueue.Name; var destination1Name = destination1.TopicName; var destination1ReceiverName = EntityNameHelper.FormatSubscriptionPath(destination1.TopicName, destination1.SubscriptionName); var destination2Name = destination2.Name; var destination2ReceiverName = destination2.Name; intermediateSender = new MessageSender(connection, intermediateQueueName); intermediateReceiver = new MessageReceiver(connection, intermediateQueueName); destination1Sender = new MessageSender(connection, destination1Name); destination1ViaSender = new MessageSender(connection, destination1Name, intermediateQueueName); destination2ViaSender = new MessageSender(connection, destination2Name, intermediateQueueName); destination1Receiver = new MessageReceiver(connection, destination1ReceiverName); destination2Receiver = new MessageReceiver(connection, destination2ReceiverName); var body = Guid.NewGuid().ToString("N"); var message1 = new Message(body.GetBytes()) { MessageId = "1", PartitionKey = "pk1" }; var message2 = new Message(body.GetBytes()) { MessageId = "2", PartitionKey = "pk2", ViaPartitionKey = "pk1" }; var message3 = new Message(body.GetBytes()) { MessageId = "3", PartitionKey = "pk3", ViaPartitionKey = "pk1" }; await intermediateSender.SendAsync(message1).ConfigureAwait(false); var receivedMessage = await intermediateReceiver.ReceiveAsync(); Assert.NotNull(receivedMessage); Assert.Equal("pk1", receivedMessage.PartitionKey); // If the transaction succeeds, then all the operations occurred on the same partition. using (var ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) { await intermediateReceiver.CompleteAsync(receivedMessage.SystemProperties.LockToken); await destination1ViaSender.SendAsync(message2); await destination2ViaSender.SendAsync(message3); ts.Complete(); } // Assert that first message indeed completed. receivedMessage = await intermediateReceiver.ReceiveAsync(ReceiveTimeout); Assert.Null(receivedMessage); // Assert that second message reached its destination. var receivedMessage1 = await destination1Receiver.ReceiveAsync(); Assert.NotNull(receivedMessage1); Assert.Equal("pk2", receivedMessage1.PartitionKey); // Assert destination1 message actually used partitionKey in the destination entity. var destination1Message = new Message(body.GetBytes()) { PartitionKey = "pk2" }; using (var ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) { await destination1Receiver.CompleteAsync(receivedMessage1.SystemProperties.LockToken); await destination1Sender.SendAsync(destination1Message); ts.Complete(); } // Assert that third message reached its destination. var receivedMessage2 = await destination2Receiver.ReceiveAsync(); Assert.NotNull(receivedMessage2); Assert.Equal("pk3", receivedMessage2.PartitionKey); await destination2Receiver.CompleteAsync(receivedMessage2.SystemProperties.LockToken); // Cleanup receivedMessage1 = await destination1Receiver.ReceiveAsync(); await destination1Receiver.CompleteAsync(receivedMessage1.SystemProperties.LockToken); } finally { // The cleanup methods will not throw and are safe to call outside of a try/catch. They // also have no dependencies on execution order, so allowing them to run in parallel is fine. await Task.WhenAll( SafeCloseAllAsync(intermediateSender, intermediateReceiver, destination1Sender, destination1ViaSender, destination2ViaSender, destination1Receiver, destination2Receiver), intermediateQueue?.CleanupAsync(), destination1?.CleanupAsync(), destination2?.CleanupAsync()); } }