public void CloneDoesNotForceAllocationOfUnpopulatedSections() { var firstBody = new List <object> { 1, 2, 3 }; var secondBody = new List <object> { 4, 5, 6 }; var body = AmqpMessageBody.FromSequence(new[] { firstBody, secondBody }); var source = new AmqpAnnotatedMessage(body); var clone = source.Clone(); // Body Assert.That(ReferenceEquals(clone.Body, source.Body), Is.False, "The message body should not be the same instance."); Assert.That(source.Body.TryGetSequence(out var sourceBody), Is.True, "The source should have a sequence body."); Assert.That(clone.Body.TryGetSequence(out var cloneBody), Is.True, "The clone should have a sequence body."); Assert.That(cloneBody, Is.EquivalentTo(sourceBody), "The body data should match."); // Other sections Assert.That(clone.HasSection(AmqpMessageSection.Body), Is.True, "The body should be populated."); Assert.That(clone.HasSection(AmqpMessageSection.Header), Is.False, "The header should not be populated."); Assert.That(clone.HasSection(AmqpMessageSection.Properties), Is.False, "The properties should not be populated."); Assert.That(clone.HasSection(AmqpMessageSection.Footer), Is.False, "The footer should be populated."); Assert.That(clone.HasSection(AmqpMessageSection.DeliveryAnnotations), Is.False, "The delivery annotations should not be populated."); Assert.That(clone.HasSection(AmqpMessageSection.MessageAnnotations), Is.False, "The message annotations should not be populated."); Assert.That(clone.HasSection(AmqpMessageSection.ApplicationProperties), Is.False, "The application properties should not be populated."); }
public async Task CanSendSequenceSection(IEnumerable <IList <object> > sequence) { await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: false)) { var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString); var sender = client.CreateSender(scope.QueueName); var msg = new ServiceBusMessage(); msg.GetRawAmqpMessage().Body = AmqpMessageBody.FromSequence(sequence); await sender.SendMessageAsync(msg); var receiver = client.CreateReceiver(scope.QueueName); var received = await receiver.ReceiveMessageAsync(); received.GetRawAmqpMessage().Body.TryGetSequence(out IEnumerable <IList <object> > receivedData); var outerEnum = receivedData.GetEnumerator(); foreach (IList <object> seq in sequence) { outerEnum.MoveNext(); var innerEnum = outerEnum.Current.GetEnumerator(); foreach (object elem in seq) { innerEnum.MoveNext(); Assert.AreEqual(elem, innerEnum.Current); } } Assert.That( () => received.Body, Throws.InstanceOf <NotSupportedException>()); } }
public void CannotUseCustomType() { Assert.That( () => AmqpMessageBody.FromValue(new Test()), Throws.InstanceOf <NotSupportedException>()); Assert.That( () => AmqpMessageBody.FromSequence(Enumerable.Repeat(new Test[] { new Test() }, 1)), Throws.InstanceOf <NotSupportedException>()); }
public void Convert_SequenceBodyMessage_Throws() { ServiceBusReceivedMessage message = ServiceBusModelFactory.ServiceBusReceivedMessage(); message.GetRawAmqpMessage().Body = AmqpMessageBody.FromSequence(new IList <object>[] { new object[] { "sequence" } }); MessageToStringConverter converter = new MessageToStringConverter(); Assert.That( () => converter.Convert(message), Throws.InstanceOf <NotSupportedException>()); }
public void CannotCreateFromNullBody() { Assert.That( () => AmqpMessageBody.FromData(data: null), Throws.InstanceOf <ArgumentNullException>()); Assert.That( () => AmqpMessageBody.FromValue(value: null), Throws.InstanceOf <ArgumentNullException>()); Assert.That( () => AmqpMessageBody.FromSequence(sequence: null), Throws.InstanceOf <ArgumentNullException>()); }
public void GetEventBodyDoesNotAllowNonDataBodyTypes(AmqpMessageBodyType bodyType) { var body = bodyType switch { AmqpMessageBodyType.Sequence => AmqpMessageBody.FromSequence(new[] { new List <object> { 1, 2, 3 } }), AmqpMessageBodyType.Value => AmqpMessageBody.FromValue("This is a value"), _ => throw new ArgumentException($"Unsupported body type { bodyType }", nameof(bodyType)) }; var message = new AmqpAnnotatedMessage(body); Assert.That(() => message.GetEventBody(), Throws.InstanceOf <NotSupportedException>()); }
public void CanCreateSequenceBody() { var sequence = new List <object>[] { new List <object> { 1, "two" }, new List <object> { 3, "four" } }; var body = AmqpMessageBody.FromSequence(sequence); Assert.AreEqual(AmqpMessageBodyType.Sequence, body.BodyType); Assert.IsTrue(body.TryGetSequence(out var outSequence)); var outList = outSequence.ToList(); Assert.AreEqual(1, outList[0][0]); Assert.AreEqual("two", outList[0][1]); Assert.AreEqual(3, outList[1][0]); Assert.AreEqual("four", outList[1][1]); Assert.IsFalse(body.TryGetData(out var data)); Assert.IsNull(data); Assert.IsFalse(body.TryGetValue(out var value)); Assert.IsNull(value); }
/// <summary> /// Creates a new message from the specified received message by copying the properties. /// </summary> /// <param name="receivedMessage">The received message to copy the data from.</param> public ServiceBusMessage(ServiceBusReceivedMessage receivedMessage) { Argument.AssertNotNull(receivedMessage, nameof(receivedMessage)); AmqpMessageBody body = null; if (receivedMessage.AmqpMessage.Body.TryGetData(out IEnumerable <ReadOnlyMemory <byte> > dataBody)) { body = AmqpMessageBody.FromData(MessageBody.FromReadOnlyMemorySegments(dataBody)); } else if (receivedMessage.AmqpMessage.Body.TryGetValue(out object valueBody)) { body = AmqpMessageBody.FromValue(valueBody); } else if (receivedMessage.AmqpMessage.Body.TryGetSequence(out IEnumerable <IList <object> > sequenceBody)) { body = AmqpMessageBody.FromSequence(sequenceBody); } else { throw new NotSupportedException($"{receivedMessage.AmqpMessage.Body.BodyType} is not a supported message body type."); } AmqpMessage = new AmqpAnnotatedMessage(body); // copy properties AmqpMessageProperties properties = AmqpMessage.Properties; AmqpMessageProperties receivedProperties = receivedMessage.AmqpMessage.Properties; properties.MessageId = receivedProperties.MessageId; properties.UserId = receivedProperties.UserId; properties.To = receivedProperties.To; properties.Subject = receivedProperties.Subject; properties.ReplyTo = receivedProperties.ReplyTo; properties.CorrelationId = receivedProperties.CorrelationId; properties.ContentType = receivedProperties.ContentType; properties.ContentEncoding = receivedProperties.ContentEncoding; properties.AbsoluteExpiryTime = receivedProperties.AbsoluteExpiryTime; properties.CreationTime = receivedProperties.CreationTime; properties.GroupId = receivedProperties.GroupId; properties.GroupSequence = receivedProperties.GroupSequence; properties.ReplyToGroupId = receivedProperties.ReplyToGroupId; // copy header except for delivery count which should be set to null AmqpMessageHeader header = AmqpMessage.Header; AmqpMessageHeader receivedHeader = receivedMessage.AmqpMessage.Header; header.DeliveryCount = null; header.Durable = receivedHeader.Durable; header.Priority = receivedHeader.Priority; header.TimeToLive = receivedHeader.TimeToLive; header.FirstAcquirer = receivedHeader.FirstAcquirer; // copy message annotations except for broker set ones foreach (KeyValuePair <string, object> kvp in receivedMessage.AmqpMessage.MessageAnnotations) { if (kvp.Key == AmqpMessageConstants.LockedUntilName || kvp.Key == AmqpMessageConstants.SequenceNumberName || kvp.Key == AmqpMessageConstants.DeadLetterSourceName || kvp.Key == AmqpMessageConstants.EnqueueSequenceNumberName || kvp.Key == AmqpMessageConstants.EnqueuedTimeUtcName || kvp.Key == AmqpMessageConstants.MessageStateName) { continue; } AmqpMessage.MessageAnnotations.Add(kvp.Key, kvp.Value); } // copy delivery annotations foreach (KeyValuePair <string, object> kvp in receivedMessage.AmqpMessage.DeliveryAnnotations) { AmqpMessage.DeliveryAnnotations.Add(kvp.Key, kvp.Value); } // copy footer foreach (KeyValuePair <string, object> kvp in receivedMessage.AmqpMessage.Footer) { AmqpMessage.Footer.Add(kvp.Key, kvp.Value); } // copy application properties except for broker set ones foreach (KeyValuePair <string, object> kvp in receivedMessage.AmqpMessage.ApplicationProperties) { if (kvp.Key == AmqpMessageConstants.DeadLetterReasonHeader || kvp.Key == AmqpMessageConstants.DeadLetterErrorDescriptionHeader) { continue; } AmqpMessage.ApplicationProperties.Add(kvp.Key, kvp.Value); } }
public static ServiceBusReceivedMessage AmqpMessageToSBMessage(AmqpMessage amqpMessage, bool isPeeked = false) { Argument.AssertNotNull(amqpMessage, nameof(amqpMessage)); AmqpAnnotatedMessage annotatedMessage; if ((amqpMessage.BodyType & SectionFlag.Data) != 0 && amqpMessage.DataBody != null) { annotatedMessage = new AmqpAnnotatedMessage(AmqpMessageBody.FromData(BodyMemory.FromAmqpData(amqpMessage.DataBody))); } else if ((amqpMessage.BodyType & SectionFlag.AmqpValue) != 0 && amqpMessage.ValueBody?.Value != null) { if (TryGetNetObjectFromAmqpObject(amqpMessage.ValueBody.Value, MappingType.MessageBody, out object netObject)) { annotatedMessage = new AmqpAnnotatedMessage(AmqpMessageBody.FromValue(netObject)); } else { throw new NotSupportedException(Resources.InvalidAmqpMessageValueBody.FormatForUser(amqpMessage.ValueBody.Value.GetType())); } } else if ((amqpMessage.BodyType & SectionFlag.AmqpSequence) != 0) { annotatedMessage = new AmqpAnnotatedMessage( AmqpMessageBody.FromSequence(amqpMessage.SequenceBody.Select(s => (IList <object>)s.List).ToList())); } // default to using an empty Data section if no data else { annotatedMessage = new AmqpAnnotatedMessage(new AmqpMessageBody(Enumerable.Empty <ReadOnlyMemory <byte> >())); } ServiceBusReceivedMessage sbMessage = new ServiceBusReceivedMessage(annotatedMessage); SectionFlag sections = amqpMessage.Sections; if ((sections & SectionFlag.Header) != 0) { if (amqpMessage.Header.Ttl != null) { annotatedMessage.Header.TimeToLive = TimeSpan.FromMilliseconds(amqpMessage.Header.Ttl.Value); } if (amqpMessage.Header.DeliveryCount != null) { annotatedMessage.Header.DeliveryCount = isPeeked ? (amqpMessage.Header.DeliveryCount.Value) : (amqpMessage.Header.DeliveryCount.Value + 1); } } if ((sections & SectionFlag.Properties) != 0) { if (amqpMessage.Properties.MessageId != null) { annotatedMessage.Properties.MessageId = new AmqpMessageId(amqpMessage.Properties.MessageId.ToString()); } if (amqpMessage.Properties.CorrelationId != null) { annotatedMessage.Properties.CorrelationId = new AmqpMessageId(amqpMessage.Properties.CorrelationId.ToString()); } if (amqpMessage.Properties.ContentType.Value != null) { annotatedMessage.Properties.ContentType = amqpMessage.Properties.ContentType.Value; } if (amqpMessage.Properties.Subject != null) { annotatedMessage.Properties.Subject = amqpMessage.Properties.Subject; } if (amqpMessage.Properties.To != null) { annotatedMessage.Properties.To = new AmqpAddress(amqpMessage.Properties.To.ToString()); } if (amqpMessage.Properties.ReplyTo != null) { annotatedMessage.Properties.ReplyTo = new AmqpAddress(amqpMessage.Properties.ReplyTo.ToString()); } if (amqpMessage.Properties.GroupId != null) { annotatedMessage.Properties.GroupId = amqpMessage.Properties.GroupId; } if (amqpMessage.Properties.ReplyToGroupId != null) { annotatedMessage.Properties.ReplyToGroupId = amqpMessage.Properties.ReplyToGroupId; } } // Do application properties before message annotations, because the application properties // can be updated by entries from message annotation. if ((sections & SectionFlag.ApplicationProperties) != 0) { foreach (var pair in amqpMessage.ApplicationProperties.Map) { if (TryGetNetObjectFromAmqpObject(pair.Value, MappingType.ApplicationProperty, out var netObject)) { annotatedMessage.ApplicationProperties[pair.Key.ToString()] = netObject; } } } if ((sections & SectionFlag.MessageAnnotations) != 0) { foreach (var pair in amqpMessage.MessageAnnotations.Map) { var key = pair.Key.ToString(); switch (key) { case AmqpMessageConstants.EnqueuedTimeUtcName: annotatedMessage.MessageAnnotations[AmqpMessageConstants.EnqueuedTimeUtcName] = pair.Value; break; case AmqpMessageConstants.ScheduledEnqueueTimeUtcName: annotatedMessage.MessageAnnotations[AmqpMessageConstants.ScheduledEnqueueTimeUtcName] = pair.Value; break; case AmqpMessageConstants.SequenceNumberName: annotatedMessage.MessageAnnotations[AmqpMessageConstants.SequenceNumberName] = pair.Value; break; case AmqpMessageConstants.EnqueueSequenceNumberName: annotatedMessage.MessageAnnotations[AmqpMessageConstants.EnqueueSequenceNumberName] = pair.Value; break; case AmqpMessageConstants.LockedUntilName: DateTimeOffset lockedUntil = (DateTime)pair.Value >= DateTimeOffset.MaxValue.UtcDateTime ? DateTimeOffset.MaxValue : (DateTime)pair.Value; annotatedMessage.MessageAnnotations[AmqpMessageConstants.LockedUntilName] = lockedUntil.UtcDateTime; break; case AmqpMessageConstants.PartitionKeyName: annotatedMessage.MessageAnnotations[AmqpMessageConstants.PartitionKeyName] = pair.Value; break; case AmqpMessageConstants.PartitionIdName: annotatedMessage.MessageAnnotations[AmqpMessageConstants.PartitionIdName] = pair.Value; break; case AmqpMessageConstants.ViaPartitionKeyName: annotatedMessage.MessageAnnotations[AmqpMessageConstants.ViaPartitionKeyName] = pair.Value; break; case AmqpMessageConstants.DeadLetterSourceName: annotatedMessage.MessageAnnotations[AmqpMessageConstants.DeadLetterSourceName] = pair.Value; break; default: if (TryGetNetObjectFromAmqpObject(pair.Value, MappingType.ApplicationProperty, out var netObject)) { annotatedMessage.MessageAnnotations[key] = netObject; } break; } } } if (amqpMessage.DeliveryTag.Count == GuidSizeInBytes) { Span <byte> guidBytes = stackalloc byte[GuidSizeInBytes]; amqpMessage.DeliveryTag.AsSpan().CopyTo(guidBytes); if (!MemoryMarshal.TryRead <Guid>(guidBytes, out var lockTokenGuid)) { lockTokenGuid = new Guid(guidBytes.ToArray()); } sbMessage.LockTokenGuid = lockTokenGuid; } amqpMessage.Dispose(); return(sbMessage); }