public void TryAddRespectsTheBatchLock() { var mockBatch = new MockTransportBatch(); var batch = new ServiceBusMessageBatch(mockBatch); var message = new ServiceBusMessage(new byte[] { 0x21 }); Assert.That(batch.TryAdd(new ServiceBusMessage(new byte[] { 0x21 })), Is.True, "The message should have been accepted before locking."); batch.Lock(); Assert.That(() => batch.TryAdd(new ServiceBusMessage(Array.Empty <byte>())), Throws.InstanceOf <InvalidOperationException>(), "The batch should not accept messages when locked."); batch.Unlock(); Assert.That(batch.TryAdd(new ServiceBusMessage(Array.Empty <byte>())), Is.True, "The message should have been accepted after unlocking."); }
public async Task TryAddReturnsFalseIfSizeExceed() { await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: false)) { await using var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString); ServiceBusSender sender = client.CreateSender(scope.QueueName); using ServiceBusMessageBatch batch = await sender.CreateBatchAsync(); // Actual limit is 262144 bytes for a single message. Assert.That(() => batch.TryAdd(new ServiceBusMessage(new byte[200000])), Is.True, "A message was rejected by the batch; all messages should be accepted."); Assert.That(() => batch.TryAdd(new ServiceBusMessage(new byte[200000])), Is.False, "A message was rejected by the batch; message size exceed."); await sender.SendAsync(batch); } }
public async Task ReceiveFromSpecificSession() { await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: true)) { string connectionString = TestEnvironment.ServiceBusConnectionString; string queueName = scope.QueueName; // since ServiceBusClient implements IAsyncDisposable we create it with "await using" await using var client = new ServiceBusClient(connectionString); // create the sender ServiceBusSender sender = client.CreateSender(queueName); // create a message batch that we can send ServiceBusMessageBatch messageBatch = await sender.CreateBatchAsync(); messageBatch.TryAdd( new ServiceBusMessage(Encoding.UTF8.GetBytes("First")) { SessionId = "Session1" }); messageBatch.TryAdd( new ServiceBusMessage(Encoding.UTF8.GetBytes("Second")) { SessionId = "Session2" }); // send the message batch await sender.SendAsync(messageBatch); #region Snippet:ServiceBusReceiveFromSpecificSession // create a receiver specifying a particular session ServiceBusSessionReceiver receiver = await client.CreateSessionReceiverAsync( queueName, new ServiceBusSessionReceiverOptions { SessionId = "Session2" }); // the received message is a different type as it contains some service set properties ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveAsync(); Console.WriteLine(receivedMessage.SessionId); #endregion Assert.AreEqual(Encoding.UTF8.GetBytes("Second"), receivedMessage.Body.AsBytes().ToArray()); Assert.AreEqual("Session2", receivedMessage.SessionId); } }
public async Task CanSendLargeMessageBatch() { await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: false)) { await using var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString); ServiceBusSender sender = client.CreateSender(scope.QueueName); using ServiceBusMessageBatch batch = await sender.CreateBatchAsync(); // Actual limit is 262144 bytes for a single message. batch.TryAdd(new ServiceBusMessage(new byte[100000 / 3])); batch.TryAdd(new ServiceBusMessage(new byte[100000 / 3])); batch.TryAdd(new ServiceBusMessage(new byte[100000 / 3])); await sender.SendAsync(batch); } }
public async Task SendAndReceiveMessageSafeBatch() { await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: false)) { string connectionString = TestEnvironment.ServiceBusConnectionString; string queueName = scope.QueueName; //@@ string connectionString = "<connection_string>"; //@@ string queueName = "<queue_name>"; // since ServiceBusClient implements IAsyncDisposable we create it with "await using" await using var client = new ServiceBusClient(connectionString); // create the sender ServiceBusSender sender = client.CreateSender(queueName); // create a message batch that we can send #region Snippet:ServiceBusSendAndReceiveSafeBatch ServiceBusMessageBatch messageBatch = await sender.CreateBatchAsync(); messageBatch.TryAdd(new ServiceBusMessage(Encoding.UTF8.GetBytes("First"))); messageBatch.TryAdd(new ServiceBusMessage(Encoding.UTF8.GetBytes("Second"))); // send the message batch await sender.SendAsync(messageBatch); #endregion // create a receiver that we can use to receive the messages ServiceBusReceiver receiver = client.CreateReceiver(queueName); // the received message is a different type as it contains some service set properties IList <ServiceBusReceivedMessage> receivedMessages = await receiver.ReceiveBatchAsync(maxMessages : 2); foreach (ServiceBusReceivedMessage receivedMessage in receivedMessages) { // get the message body as a string string body = Encoding.UTF8.GetString(receivedMessage.Body.ToArray()); Console.WriteLine(body); } var sentMessagesEnum = messageBatch.AsEnumerable <ServiceBusMessage>().GetEnumerator(); foreach (ServiceBusReceivedMessage receivedMessage in receivedMessages) { sentMessagesEnum.MoveNext(); Assert.AreEqual(sentMessagesEnum.Current.Body.ToArray(), receivedMessage.Body.ToArray()); } } }
public async Task SendBatchManagesLockingTheBatch() { using var cancellationSource = new CancellationTokenSource(); cancellationSource.CancelAfter(TimeSpan.FromSeconds(15)); var completionSource = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously); var mockTransportBatch = new Mock <TransportMessageBatch>(); var batch = new ServiceBusMessageBatch(mockTransportBatch.Object); var mockTransportSender = new Mock <TransportSender>(); var mockConnection = new Mock <ServiceBusConnection>(); mockConnection .Setup(connection => connection.RetryOptions) .Returns(new ServiceBusRetryOptions()); mockConnection .Setup(connection => connection.CreateTransportSender(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <ServiceBusRetryPolicy>(), It.IsAny <string>())) .Returns(mockTransportSender.Object); mockConnection .Setup(connection => connection.ThrowIfClosed()); mockTransportBatch .Setup(transport => transport.TryAdd(It.IsAny <ServiceBusMessage>())) .Returns(true); mockTransportSender .Setup(transport => transport.SendBatchAsync(It.IsAny <ServiceBusMessageBatch>(), It.IsAny <CancellationToken>())) .Returns(async() => await Task.WhenAny(completionSource.Task, Task.Delay(Timeout.Infinite, cancellationSource.Token))); Assert.That(batch.TryAdd(new ServiceBusMessage(Array.Empty <byte>())), Is.True, "The batch should not be locked before sending."); var sender = new ServiceBusSender("dummy", null, mockConnection.Object); var sendTask = sender.SendAsync(batch); Assert.That(() => batch.TryAdd(new ServiceBusMessage(Array.Empty <byte>())), Throws.InstanceOf <InvalidOperationException>(), "The batch should be locked while sending."); completionSource.TrySetResult(true); await sendTask; Assert.That(cancellationSource.IsCancellationRequested, Is.False, "The cancellation token should not have been signaled."); Assert.That(batch.TryAdd(new ServiceBusMessage(Array.Empty <byte>())), Is.True, "The batch should not be locked after sending."); cancellationSource.Cancel(); }
protected ServiceBusMessageBatch AddMessages(ServiceBusMessageBatch batch, int count, string sessionId = null, string partitionKey = null) { for (int i = 0; i < count; i++) { Assert.That(() => batch.TryAdd(GetMessage(sessionId, partitionKey)), Is.True, "A message was rejected by the batch; all messages should be accepted."); } return(batch); }
public void TryAddIsDelegatedToTheTransportClient() { var mockBatch = new MockTransportBatch(); var batch = new ServiceBusMessageBatch(mockBatch); var message = new ServiceBusMessage(new byte[] { 0x21 }); Assert.That(batch.TryAdd(message), Is.True, "The message should have been accepted."); Assert.That(mockBatch.TryAddCalledWith, Is.SameAs(message), "The message should have been passed with delegation."); }
public async Task CanSendAnEmptyBodyMessageBatch() { await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: false)) { await using var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString); ServiceBusSender sender = client.CreateSender(scope.QueueName); using ServiceBusMessageBatch batch = await sender.CreateBatchAsync(); batch.TryAdd(new ServiceBusMessage(Array.Empty <byte>())); await sender.SendAsync(batch); } }
public async Task ProcessSessionMessages() { await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: true)) { string connectionString = TestEnvironment.ServiceBusConnectionString; string queueName = scope.QueueName; await using var client = GetClient(); #region Snippet:ServiceBusProcessSessionMessages //@@ string connectionString = "<connection_string>"; //@@ string queueName = "<queue_name>"; // since ServiceBusClient implements IAsyncDisposable we create it with "await using" //@@ await using var client = new ServiceBusClient(connectionString); // get the sender ServiceBusSender sender = client.GetSender(queueName); // create a message batch that we can send ServiceBusMessageBatch messageBatch = await sender.CreateBatchAsync(); messageBatch.TryAdd( new ServiceBusMessage(Encoding.UTF8.GetBytes("First")) { SessionId = "Session1" }); messageBatch.TryAdd( new ServiceBusMessage(Encoding.UTF8.GetBytes("Second")) { SessionId = "Session2" }); // send the message batch await sender.SendBatchAsync(messageBatch); // get the options to use for configuring the processor var options = new ServiceBusProcessorOptions { // By default after the message handler returns, the processor will complete the message // If I want more fine-grained control over settlement, I can set this to false. AutoComplete = false, // I can also allow for multi-threading MaxConcurrentCalls = 2 }; // get a session processor that we can use to process the messages ServiceBusSessionProcessor processor = client.GetSessionProcessor(queueName, options); // since the message handler will run in a background thread, in order to prevent // this sample from terminating immediately, we can use a task completion source that // we complete from within the message handler. TaskCompletionSource <bool> tcs = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously); processor.ProcessMessageAsync += MessageHandler; processor.ProcessErrorAsync += ErrorHandler; async Task MessageHandler(ProcessSessionMessageEventArgs args) { string body = Encoding.Default.GetString(args.Message.Body.ToArray()); Console.WriteLine(body); // we can evaluate application logic and use that to determine how to settle the message. await args.CompleteAsync(args.Message); // we can also set arbitrary session state using this receiver // the state is specific to the session, and not any particular message await args.SetSessionStateAsync(Encoding.Default.GetBytes("some state")); tcs.SetResult(true); } Task ErrorHandler(ProcessErrorEventArgs args) { // the error source tells me at what point in the processing an error occurred Console.WriteLine(args.ErrorSource); // the fully qualified namespace is available Console.WriteLine(args.FullyQualifiedNamespace); // as well as the entity path Console.WriteLine(args.EntityPath); Console.WriteLine(args.Exception.ToString()); return(Task.CompletedTask); } await processor.StartProcessingAsync(); // await our task completion source task so that the message handler will be invoked at least once. await tcs.Task; // stop processing once the task completion source was completed. await processor.StopProcessingAsync(); #endregion } }