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); }
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 } }