Example #1
0
        public async Task CrossEntityTransactionReceivesFirstRollback()
        {
            await using var client = CreateCrossEntityTxnClient();
            await using var queueA = await ServiceBusScope.CreateWithQueue(enablePartitioning : false, enableSession : false);

            await using var queueB = await ServiceBusScope.CreateWithQueue(enablePartitioning : false, enableSession : false);

            await using var topicC = await ServiceBusScope.CreateWithTopic(enablePartitioning : false, enableSession : false);

            await using var noTxClient = CreateClient();
            var senderA   = noTxClient.CreateSender(queueA.QueueName);
            var receiverA = client.CreateReceiver(queueA.QueueName);
            var senderB   = client.CreateSender(queueB.QueueName);
            var senderC   = client.CreateSender(topicC.TopicName);

            var message = new ServiceBusMessage();

            await senderA.SendMessageAsync(message);

            ServiceBusReceivedMessage receivedMessage = await receiverA.ReceiveMessageAsync();

            using (var ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
                await receiverA.CompleteMessageAsync(receivedMessage);

                await senderB.SendMessageAsync(message);

                await senderC.SendMessageAsync(message);
            }
            await receiverA.AbandonMessageAsync(receivedMessage);

            // transaction wasn't committed - verify that it was rolled back
            receivedMessage = await receiverA.ReceiveMessageAsync();

            Assert.IsNotNull(receivedMessage);
            await receiverA.AbandonMessageAsync(receivedMessage);

            var receiverB = noTxClient.CreateReceiver(queueB.QueueName);

            receivedMessage = await receiverB.ReceiveMessageAsync(TimeSpan.FromSeconds(10));

            Assert.IsNull(receivedMessage);

            var receiverC = noTxClient.CreateReceiver(topicC.TopicName, topicC.SubscriptionNames.First());

            receivedMessage = await receiverC.ReceiveMessageAsync(TimeSpan.FromSeconds(10));

            Assert.IsNull(receivedMessage);

            receivedMessage = await receiverA.ReceiveMessageAsync();

            // now commit the transaction
            using (var ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
                await receiverA.CompleteMessageAsync(receivedMessage);

                await senderB.SendMessageAsync(message);

                await senderC.SendMessageAsync(message);

                ts.Complete();
            }
            receivedMessage = await receiverA.ReceiveMessageAsync(TimeSpan.FromSeconds(10));

            Assert.IsNull(receivedMessage);
            receivedMessage = await receiverB.ReceiveMessageAsync();

            Assert.IsNotNull(receivedMessage);
            receivedMessage = await receiverC.ReceiveMessageAsync();

            Assert.IsNotNull(receivedMessage);
        }
        public async Task AddGetAndRemoveRules()
        {
            await using (var scope = await ServiceBusScope.CreateWithTopic(enablePartitioning: false, enableSession: false))
            {
                await using var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString);

                ServiceBusRuleManager ruleManager = client.CreateRuleManager(scope.TopicName, scope.SubscriptionNames.First());
                var sqlRuleName         = "sqlRule";
                var correlationRuleName = "correlationRule";

                var rules = (await ruleManager.GetRulesAsync()).ToList();
                Assert.AreEqual(1, rules.Count());
                var firstRule = rules[0];
                Assert.AreEqual(RuleDescription.DefaultRuleName, firstRule.Name);
                Assert.Null(firstRule.Action);

                await ruleManager.AddRuleAsync(sqlRuleName, new SqlRuleFilter("price > 10"));

                var ruleDescription = new RuleDescription(correlationRuleName)
                {
                    Filter = new CorrelationRuleFilter
                    {
                        CorrelationId = "correlationId",
                        Label         = "label",
                        MessageId     = "messageId",
                        Properties    =
                        {
                            { "key1", "value1" }
                        },
                        ReplyTo          = "replyTo",
                        ReplyToSessionId = "replyToSessionId",
                        SessionId        = "sessionId",
                        To = "to"
                    },
                    Action = new SqlRuleAction("Set CorrelationId = 'newValue'")
                };
                await ruleManager.AddRuleAsync(ruleDescription);

                rules = (await ruleManager.GetRulesAsync()).ToList();
                Assert.AreEqual(3, rules.Count);

                var sqlRule = rules.FirstOrDefault(rule => rule.Name.Equals(sqlRuleName));
                Assert.NotNull(sqlRule);
                Assert.Null(sqlRule.Action);
                Assert.IsInstanceOf <SqlRuleFilter>(sqlRule.Filter);
                Assert.AreEqual("price > 10", ((SqlRuleFilter)sqlRule.Filter).SqlExpression);

                var correlationRule = rules.FirstOrDefault(rule => rule.Name.Equals(correlationRuleName));
                Assert.NotNull(correlationRule);
                Assert.IsInstanceOf <SqlRuleAction>(correlationRule.Action);
                var sqlRuleAction = correlationRule.Action as SqlRuleAction;
                Assert.NotNull(sqlRuleAction);
                Assert.AreEqual("Set CorrelationId = 'newValue'", sqlRuleAction.SqlExpression);
                Assert.IsInstanceOf <CorrelationRuleFilter>(correlationRule.Filter);
                var correlationRuleFilter = correlationRule.Filter as CorrelationRuleFilter;
                Assert.NotNull(correlationRuleFilter);
                Assert.AreEqual("correlationId", correlationRuleFilter.CorrelationId);
                Assert.AreEqual("label", correlationRuleFilter.Label);
                Assert.AreEqual("messageId", correlationRuleFilter.MessageId);
                Assert.AreEqual("replyTo", correlationRuleFilter.ReplyTo);
                Assert.AreEqual("replyToSessionId", correlationRuleFilter.ReplyToSessionId);
                Assert.AreEqual("sessionId", correlationRuleFilter.SessionId);
                Assert.AreEqual("to", correlationRuleFilter.To);
                Assert.NotNull(correlationRuleFilter.Properties);
                Assert.AreEqual("value1", correlationRuleFilter.Properties["key1"]);

                await ruleManager.RemoveRuleAsync(RuleDescription.DefaultRuleName);

                await ruleManager.RemoveRuleAsync(sqlRuleName);

                await ruleManager.RemoveRuleAsync(correlationRuleName);

                rules = (await ruleManager.GetRulesAsync()).ToList();
                Assert.AreEqual(0, rules.Count());
            }
        }
        public async Task DeadLetterMessagesSubscription(bool useSpecificSession)
        {
            await using (var scope = await ServiceBusScope.CreateWithTopic(enablePartitioning: false, enableSession: true))
            {
                await using var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString);
                ServiceBusSender sender = client.CreateSender(scope.TopicName);
                var messageCount        = 10;
                var sessionId           = "sessionId1";
                using ServiceBusMessageBatch batch = await sender.CreateMessageBatchAsync();

                IEnumerable <ServiceBusMessage> messages = AddMessages(batch, messageCount, sessionId).AsEnumerable <ServiceBusMessage>();

                await sender.SendMessagesAsync(batch);

                var topicName        = scope.TopicName;
                var subscriptionName = scope.SubscriptionNames.First();

                var receiver = await client.AcceptSessionAsync(
                    topicName : topicName,
                    subscriptionName : subscriptionName,
                    useSpecificSession?sessionId : null);

                var remainingMessages = messageCount;
                var messageEnum       = messages.GetEnumerator();

                while (remainingMessages > 0)
                {
                    foreach (var item in await receiver.ReceiveMessagesAsync(remainingMessages))
                    {
                        remainingMessages--;
                        messageEnum.MoveNext();
                        Assert.AreEqual(messageEnum.Current.MessageId, item.MessageId);
                        Assert.AreEqual(messageEnum.Current.SessionId, item.SessionId);
                        var props = new Dictionary <string, object>();
                        // these should be ignored by DeadLetter property getters as they are not strings
                        props[AmqpMessageConstants.DeadLetterReasonHeader]           = DateTime.UtcNow;
                        props[AmqpMessageConstants.DeadLetterErrorDescriptionHeader] = DateTime.UtcNow;

                        await receiver.DeadLetterMessageAsync(item, props);
                    }
                }
                Assert.AreEqual(0, remainingMessages);

                var peekedMessage = receiver.PeekMessageAsync();
                Assert.IsNull(peekedMessage.Result);

                messageEnum.Reset();
                remainingMessages = messageCount;
                var deadLetterReceiver = client.CreateReceiver(topicName, subscriptionName, new ServiceBusReceiverOptions
                {
                    SubQueue = SubQueue.DeadLetter
                });

                while (remainingMessages > 0)
                {
                    foreach (var msg in await deadLetterReceiver.ReceiveMessagesAsync(remainingMessages))
                    {
                        remainingMessages--;
                        messageEnum.MoveNext();
                        Assert.AreEqual(messageEnum.Current.MessageId, msg.MessageId);
                        Assert.AreEqual(messageEnum.Current.SessionId, msg.SessionId);
                        Assert.IsNull(msg.DeadLetterErrorDescription);
                        Assert.IsNull(msg.DeadLetterReason);
                        Assert.IsNotNull(msg.ApplicationProperties[AmqpMessageConstants.DeadLetterReasonHeader]);
                        Assert.IsNotNull(msg.ApplicationProperties[AmqpMessageConstants.DeadLetterErrorDescriptionHeader]);
                        await deadLetterReceiver.CompleteMessageAsync(msg);
                    }
                }
                Assert.AreEqual(0, remainingMessages);

                var deadLetterMessage = await deadLetterReceiver.PeekMessageAsync();

                Assert.IsNull(deadLetterMessage);
            }
        }
        public async Task TransactionalSendViaCommitTest()
        {
            var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString);

            await using var intermediateQueue = await ServiceBusScope.CreateWithQueue(enablePartitioning : true, enableSession : false);

            await using var destination1 = await ServiceBusScope.CreateWithTopic(enablePartitioning : true, enableSession : false);

            await using var destination2 = await ServiceBusScope.CreateWithQueue(enablePartitioning : true, enableSession : false);

            var intermediateSender    = client.CreateSender(intermediateQueue.QueueName);
            var intermediateReceiver  = client.CreateReceiver(intermediateQueue.QueueName);
            var destination1Sender    = client.CreateSender(destination1.TopicName);
            var destination1ViaSender = client.CreateSender(destination1.TopicName, new ServiceBusSenderOptions
            {
                ViaQueueOrTopicName = intermediateQueue.QueueName
            });
            var destination2ViaSender = client.CreateSender(destination2.QueueName, new ServiceBusSenderOptions
            {
                ViaQueueOrTopicName = intermediateQueue.QueueName
            });
            var destination1Receiver = client.CreateReceiver(destination1.TopicName, destination1.SubscriptionNames.First());
            var destination2Receiver = client.CreateReceiver(destination2.QueueName);

            var body     = Encoding.Default.GetBytes(Guid.NewGuid().ToString("N"));
            var message1 = new ServiceBusMessage(body)
            {
                MessageId = "1", PartitionKey = "pk1"
            };
            var message2 = new ServiceBusMessage(body)
            {
                MessageId = "2", PartitionKey = "pk2", ViaPartitionKey = "pk1"
            };
            var message3 = new ServiceBusMessage(body)
            {
                MessageId = "3", PartitionKey = "pk3", ViaPartitionKey = "pk1"
            };

            await intermediateSender.SendMessageAsync(message1).ConfigureAwait(false);

            var receivedMessage = await intermediateReceiver.ReceiveMessageAsync();

            Assert.NotNull(receivedMessage);
            Assert.AreEqual("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.CompleteMessageAsync(receivedMessage);

                await destination1ViaSender.SendMessageAsync(message2);

                await destination2ViaSender.SendMessageAsync(message3);

                ts.Complete();
            }

            // Assert that first message indeed completed.
            receivedMessage = await intermediateReceiver.ReceiveMessageAsync(TimeSpan.FromSeconds(5));

            Assert.Null(receivedMessage);

            // Assert that second message reached its destination.
            var receivedMessage1 = await destination1Receiver.ReceiveMessageAsync();

            Assert.NotNull(receivedMessage1);
            Assert.AreEqual("pk2", receivedMessage1.PartitionKey);

            // Assert destination1 message actually used partitionKey in the destination entity.
            var destination1Message = new ServiceBusMessage(body)
            {
                PartitionKey = "pk2"
            };

            using (var ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
                await destination1Receiver.CompleteMessageAsync(receivedMessage1);

                await destination1Sender.SendMessageAsync(destination1Message);

                ts.Complete();
            }

            // Assert that third message reached its destination.
            var receivedMessage2 = await destination2Receiver.ReceiveMessageAsync();

            Assert.NotNull(receivedMessage2);
            Assert.AreEqual("pk3", receivedMessage2.PartitionKey);
            await destination2Receiver.CompleteMessageAsync(receivedMessage2);

            // Cleanup
            receivedMessage1 = await destination1Receiver.ReceiveMessageAsync();

            await destination1Receiver.CompleteMessageAsync(receivedMessage1);
        }
        public async Task CreateFromReceivedMessageCopiesPropertiesTopic()
        {
            await using (var scope = await ServiceBusScope.CreateWithTopic(enablePartitioning: true, enableSession: true))
            {
                var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString);
                var sender = client.CreateSender(scope.TopicName);
                var msg    = new ServiceBusMessage(new BinaryData(ServiceBusTestUtilities.GetRandomBuffer(100)));
                msg.ContentType   = "contenttype";
                msg.CorrelationId = "correlationid";
                msg.Subject       = "label";
                msg.MessageId     = "messageId";
                msg.PartitionKey  = "key";
                msg.ApplicationProperties.Add("testProp", "my prop");
                msg.ReplyTo              = "replyto";
                msg.ReplyToSessionId     = "replytosession";
                msg.ScheduledEnqueueTime = DateTimeOffset.Now;
                msg.SessionId            = "key";
                msg.TimeToLive           = TimeSpan.FromSeconds(60);
                msg.To = "to";
                await sender.SendMessageAsync(msg);

                ServiceBusSessionReceiver receiver = await client.AcceptNextSessionAsync(scope.TopicName, scope.SubscriptionNames.First());

                ServiceBusReceivedMessage received = await receiver.ReceiveMessageAsync();

                AmqpAnnotatedMessage rawReceived = received.GetRawAmqpMessage();
                Assert.IsNotNull(rawReceived.Header.DeliveryCount);
                Assert.IsTrue(rawReceived.MessageAnnotations.ContainsKey(AmqpMessageConstants.LockedUntilName));
                Assert.IsTrue(rawReceived.MessageAnnotations.ContainsKey(AmqpMessageConstants.SequenceNumberName));
                Assert.IsTrue(rawReceived.MessageAnnotations.ContainsKey(AmqpMessageConstants.EnqueueSequenceNumberName));
                Assert.IsTrue(rawReceived.MessageAnnotations.ContainsKey(AmqpMessageConstants.EnqueuedTimeUtcName));

                AssertMessagesEqual(msg, received);
                var toSend = new ServiceBusMessage(received);
                AmqpAnnotatedMessage rawSend = toSend.GetRawAmqpMessage();

                // verify that all system set properties have been cleared out
                Assert.IsNull(rawSend.Header.DeliveryCount);
                Assert.IsFalse(rawSend.MessageAnnotations.ContainsKey(AmqpMessageConstants.LockedUntilName));
                Assert.IsFalse(rawSend.MessageAnnotations.ContainsKey(AmqpMessageConstants.SequenceNumberName));
                Assert.IsFalse(rawSend.MessageAnnotations.ContainsKey(AmqpMessageConstants.DeadLetterSourceName));
                Assert.IsFalse(rawSend.MessageAnnotations.ContainsKey(AmqpMessageConstants.EnqueueSequenceNumberName));
                Assert.IsFalse(rawSend.MessageAnnotations.ContainsKey(AmqpMessageConstants.EnqueuedTimeUtcName));
                Assert.IsFalse(rawSend.MessageAnnotations.ContainsKey(AmqpMessageConstants.DeadLetterSourceName));
                Assert.IsFalse(toSend.ApplicationProperties.ContainsKey(AmqpMessageConstants.DeadLetterReasonHeader));
                Assert.IsFalse(toSend.ApplicationProperties.ContainsKey(AmqpMessageConstants.DeadLetterErrorDescriptionHeader));

                AssertMessagesEqual(toSend, received);

                void AssertMessagesEqual(ServiceBusMessage sentMessage, ServiceBusReceivedMessage received)
                {
                    Assert.IsTrue(received.Body.ToArray().SequenceEqual(sentMessage.Body.ToArray()));
                    Assert.AreEqual(received.ContentType, sentMessage.ContentType);
                    Assert.AreEqual(received.CorrelationId, sentMessage.CorrelationId);
                    Assert.AreEqual(received.Subject, sentMessage.Subject);
                    Assert.AreEqual(received.ContentType, sentMessage.ContentType);
                    Assert.AreEqual(received.CorrelationId, sentMessage.CorrelationId);
                    Assert.AreEqual(received.MessageId, sentMessage.MessageId);
                    Assert.AreEqual(received.PartitionKey, sentMessage.PartitionKey);
                    Assert.AreEqual((string)received.ApplicationProperties["testProp"], (string)sentMessage.ApplicationProperties["testProp"]);
                    Assert.AreEqual(received.ReplyTo, sentMessage.ReplyTo);
                    Assert.AreEqual(received.ReplyToSessionId, sentMessage.ReplyToSessionId);
                    Assert.AreEqual(received.ScheduledEnqueueTime.UtcDateTime.Second, sentMessage.ScheduledEnqueueTime.UtcDateTime.Second);
                    Assert.AreEqual(received.SessionId, sentMessage.SessionId);
                    Assert.AreEqual(received.TimeToLive, sentMessage.TimeToLive);
                    Assert.AreEqual(received.To, sentMessage.To);
                    Assert.AreEqual(received.TransactionPartitionKey, sentMessage.TransactionPartitionKey);
                }
            }
        }
        public async Task TransactionGroupReceivesFirst(bool partitioned, bool enableSessions)
        {
            var transactionGroup = "myTxn";

            await using var client = CreateClient();
            await using var queueA = await ServiceBusScope.CreateWithQueue(enablePartitioning : partitioned, enableSession : enableSessions);

            await using var queueB = await ServiceBusScope.CreateWithQueue(enablePartitioning : partitioned, enableSession : enableSessions);

            await using var topicC = await ServiceBusScope.CreateWithTopic(enablePartitioning : partitioned, enableSession : enableSessions);

            var senderA = client.CreateSender(queueA.QueueName);
            ServiceBusReceiver receiverA = null;

            if (!enableSessions)
            {
                receiverA = client.CreateReceiver(queueA.QueueName, new ServiceBusReceiverOptions
                {
                    TransactionGroup = transactionGroup
                });
            }
            var senderB = client.CreateSender(queueB.QueueName, new ServiceBusSenderOptions
            {
                TransactionGroup = transactionGroup
            });
            var senderC = client.CreateSender(topicC.TopicName, new ServiceBusSenderOptions
            {
                TransactionGroup = transactionGroup
            });

            var message = new ServiceBusMessage
            {
                SessionId = enableSessions ? "sessionId" : null,
                TransactionPartitionKey = partitioned ? "sessionId" : null
            };

            await senderA.SendMessageAsync(message);

            if (enableSessions)
            {
                receiverA = await client.AcceptNextSessionAsync(queueA.QueueName, new ServiceBusSessionReceiverOptions
                {
                    TransactionGroup = transactionGroup
                });
            }

            ServiceBusReceivedMessage receivedMessage = await receiverA.ReceiveMessageAsync();

            // If the transaction succeeds, then all the operations occurred on the same partition.
            using (var ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
                await receiverA.CompleteMessageAsync(receivedMessage);

                await senderB.SendMessageAsync(message);

                await senderC.SendMessageAsync(message);

                ts.Complete();
            }

            receivedMessage = await receiverA.ReceiveMessageAsync();

            Assert.IsNull(receivedMessage);
        }
Example #7
0
        public async Task ManageRules()
        {
            await using (var scope = await ServiceBusScope.CreateWithTopic(enablePartitioning: false, enableSession: false))
            {
                #region Snippet:ServiceBusManageRules
#if SNIPPET
                string connectionString = "<connection_string>";
                string topicName        = "<topic_name>";
                string subscriptionName = "<subscription_name>";
#else
                string connectionString = TestEnvironment.ServiceBusConnectionString;
                string topicName        = scope.TopicName;
                string subscriptionName = scope.SubscriptionNames.First();
#endif

                await using var client = new ServiceBusClient(connectionString);

                await using ServiceBusRuleManager ruleManager = client.CreateRuleManager(topicName, subscriptionName);

                // By default, subscriptions are created with a default rule that always evaluates to True. In order to filter, we need
                // to delete the default rule. You can skip this step if you create the subscription with the ServiceBusAdministrationClient,
                // and specify a the FalseRuleFilter in the create rule options.
                await ruleManager.DeleteRuleAsync(RuleProperties.DefaultRuleName);

                await ruleManager.CreateRuleAsync("brand-filter", new CorrelationRuleFilter { Subject = "Toyota" });

                // create the sender
                ServiceBusSender sender = client.CreateSender(topicName);

                ServiceBusMessage[] messages =
                {
                    new ServiceBusMessage {
                        Subject = "Ford", ApplicationProperties ={                         { "Price", 25000 } }
                    },
                    new ServiceBusMessage {
                        Subject = "Toyota", ApplicationProperties ={                         { "Price", 28000 } }
                    },
                    new ServiceBusMessage {
                        Subject = "Honda", ApplicationProperties ={                         { "Price", 35000 } }
                    }
                };

                // send the messages
                await sender.SendMessagesAsync(messages);

                // create a receiver for our subscription that we can use to receive and settle the message
                ServiceBusReceiver receiver = client.CreateReceiver(topicName, subscriptionName);

                // receive the message - we only get back the Toyota message
                while (true)
                {
                    ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync(TimeSpan.FromSeconds(5));

                    if (receivedMessage == null)
                    {
                        break;
                    }
                    Console.WriteLine($"Brand: {receivedMessage.Subject}, Price: {receivedMessage.ApplicationProperties["Price"]}");
                    await receiver.CompleteMessageAsync(receivedMessage);
                }

                await ruleManager.CreateRuleAsync("price-filter", new SqlRuleFilter("Price < 30000"));

                await ruleManager.DeleteRuleAsync("brand-filter");

                // we can also use the rule manager to iterate over the rules on the subscription.
                await foreach (RuleProperties rule in ruleManager.GetRulesAsync())
                {
                    // we should only have 1 rule at this point - "price-filter"
                    Console.WriteLine(rule.Name);
                }

                // send the messages again - because the subscription rules are evaluated when the messages are first enqueued, adding rules
                // for messages that are already in a subscription would have no effect.
                await sender.SendMessagesAsync(messages);

                // receive the messages - we get back both the Ford and the Toyota
                while (true)
                {
                    ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync(TimeSpan.FromSeconds(5));

                    if (receivedMessage == null)
                    {
                        break;
                    }
                    Console.WriteLine($"Brand: {receivedMessage.Subject}, Price: {receivedMessage.ApplicationProperties["Price"]}");
                }
                #endregion
            }
        }