From 8fabb071359ac28e046abda9cb7142b2d6cc6be6 Mon Sep 17 00:00:00 2001 From: Fermin Saez Date: Sat, 8 Feb 2025 19:40:52 +0100 Subject: [PATCH 1/2] feat: can customize the property name that holds the payload type id in the message metadata --- .../MessageDispatchRegistration.cs | 13 ++++ .../Configuration/ReceiverOptions.cs | 7 ++ .../MessageHelper.cs | 8 +- .../MessageReception/MessageContext.cs | 8 +- .../UserProperties.cs | 2 +- src/Ev.ServiceBus/Dispatch/DispatchSender.cs | 4 +- .../Wrappers/ComposedReceiverOptions.cs | 6 +- .../Management/Wrappers/ReceiverWrapper.cs | 2 +- .../Wrappers/SessionReceiverWrapper.cs | 2 +- .../Reception/ReceptionRegistrationBuilder.cs | 9 +++ .../TestMessageHelper.cs | 4 +- tests/Ev.ServiceBus.UnitTests/DispatchTest.cs | 77 +++++++++++++++---- .../EventListenerTests.cs | 15 ++-- .../MessageMetadataTests.cs | 18 +++-- .../Ev.ServiceBus.UnitTests/ReceptionTest.cs | 2 +- 15 files changed, 134 insertions(+), 43 deletions(-) diff --git a/src/Ev.ServiceBus.Abstractions/Configuration/MessageDispatchRegistration.cs b/src/Ev.ServiceBus.Abstractions/Configuration/MessageDispatchRegistration.cs index 27d4496..10dc24c 100644 --- a/src/Ev.ServiceBus.Abstractions/Configuration/MessageDispatchRegistration.cs +++ b/src/Ev.ServiceBus.Abstractions/Configuration/MessageDispatchRegistration.cs @@ -39,6 +39,8 @@ public MessageDispatchRegistration( /// public Type PayloadType { get; } + public string? PayloadTypeIdProperty { get; private set; } + /// /// Sets the PayloadTypeId (by default it will take the of the payload object) /// @@ -56,6 +58,17 @@ public MessageDispatchRegistration CustomizePayloadTypeId(string payloadId) return this; } + /// + /// Sets the PayloadTypeIdProperty from Metadata used to store the PayloadTypeId + /// + /// + /// + public MessageDispatchRegistration CustomizePayloadTypeIdProperty(string payloadTypeIdProperty) + { + PayloadTypeIdProperty = payloadTypeIdProperty; + return this; + } + /// /// This method give you the possibility to customize outgoing messages right before they are dispatched. /// diff --git a/src/Ev.ServiceBus.Abstractions/Configuration/ReceiverOptions.cs b/src/Ev.ServiceBus.Abstractions/Configuration/ReceiverOptions.cs index 7a917e3..e147d1d 100644 --- a/src/Ev.ServiceBus.Abstractions/Configuration/ReceiverOptions.cs +++ b/src/Ev.ServiceBus.Abstractions/Configuration/ReceiverOptions.cs @@ -41,4 +41,11 @@ public void EnableSessionHandling(Action conf { SessionProcessorOptions = config; } + + public string? PayloadTypeIdProperty { get; private set; } + + public void WithCustomPayloadTypeIdProperty(string payloadTypeIdProperty) + { + PayloadTypeIdProperty = payloadTypeIdProperty; + } } \ No newline at end of file diff --git a/src/Ev.ServiceBus.Abstractions/MessageHelper.cs b/src/Ev.ServiceBus.Abstractions/MessageHelper.cs index b39a2e7..2c3314b 100644 --- a/src/Ev.ServiceBus.Abstractions/MessageHelper.cs +++ b/src/Ev.ServiceBus.Abstractions/MessageHelper.cs @@ -4,9 +4,9 @@ namespace Ev.ServiceBus.Abstractions; public static class MessageHelper { - public static string? GetPayloadTypeId(this ServiceBusReceivedMessage message) + public static string? GetPayloadTypeId(this ServiceBusReceivedMessage message, string? payloadTypeIdProperty) { - return TryGetValue(message, UserProperties.PayloadTypeIdProperty); + return TryGetValue(message, payloadTypeIdProperty ?? UserProperties.DefaultPayloadTypeIdProperty); } private static string? TryGetValue(ServiceBusReceivedMessage message, string propertyName) @@ -15,7 +15,7 @@ public static class MessageHelper return value as string; } - public static ServiceBusMessage CreateMessage(string contentType, byte[] body, string payloadTypeId) + public static ServiceBusMessage CreateMessage(string contentType, byte[] body, string payloadTypeId, string? payloadTypeIdProperty) { var message = new ServiceBusMessage(body) { @@ -24,7 +24,7 @@ public static ServiceBusMessage CreateMessage(string contentType, byte[] body, s ApplicationProperties = { {UserProperties.MessageTypeProperty, "IntegrationEvent"}, - {UserProperties.PayloadTypeIdProperty, payloadTypeId} + {payloadTypeIdProperty ?? UserProperties.DefaultPayloadTypeIdProperty, payloadTypeId} } }; return message; diff --git a/src/Ev.ServiceBus.Abstractions/MessageReception/MessageContext.cs b/src/Ev.ServiceBus.Abstractions/MessageReception/MessageContext.cs index 363fe04..ec29d0a 100644 --- a/src/Ev.ServiceBus.Abstractions/MessageReception/MessageContext.cs +++ b/src/Ev.ServiceBus.Abstractions/MessageReception/MessageContext.cs @@ -8,24 +8,24 @@ namespace Ev.ServiceBus.Abstractions; public class MessageContext { - public MessageContext(ProcessSessionMessageEventArgs args, ClientType clientType, string resourceId) + public MessageContext(ProcessSessionMessageEventArgs args, ClientType clientType, string resourceId, string? payloadTypeIdProperty) { SessionArgs = args; ClientType = clientType; ResourceId = resourceId; Message = args.Message; CancellationToken = args.CancellationToken; - PayloadTypeId = Message.GetPayloadTypeId(); + PayloadTypeId = Message.GetPayloadTypeId(payloadTypeIdProperty); } - public MessageContext(ProcessMessageEventArgs args, ClientType clientType, string resourceId) + public MessageContext(ProcessMessageEventArgs args, ClientType clientType, string resourceId, string? payloadTypeIdProperty) { Args = args; ClientType = clientType; ResourceId = resourceId; Message = args.Message; CancellationToken = args.CancellationToken; - PayloadTypeId = Message.GetPayloadTypeId(); + PayloadTypeId = Message.GetPayloadTypeId(payloadTypeIdProperty); } public ServiceBusReceivedMessage Message { get; } diff --git a/src/Ev.ServiceBus.Abstractions/UserProperties.cs b/src/Ev.ServiceBus.Abstractions/UserProperties.cs index 51b48c8..bec8d83 100644 --- a/src/Ev.ServiceBus.Abstractions/UserProperties.cs +++ b/src/Ev.ServiceBus.Abstractions/UserProperties.cs @@ -5,6 +5,6 @@ /// public static class UserProperties { - public const string PayloadTypeIdProperty = "PayloadTypeId"; + public const string DefaultPayloadTypeIdProperty = "PayloadTypeId"; public const string MessageTypeProperty = "MessageType"; } \ No newline at end of file diff --git a/src/Ev.ServiceBus/Dispatch/DispatchSender.cs b/src/Ev.ServiceBus/Dispatch/DispatchSender.cs index be8e3fa..d6ed358 100644 --- a/src/Ev.ServiceBus/Dispatch/DispatchSender.cs +++ b/src/Ev.ServiceBus/Dispatch/DispatchSender.cs @@ -213,9 +213,9 @@ private ServiceBusMessage CreateMessage( { var originalCorrelationId = _messageMetadataAccessor.Metadata?.CorrelationId ?? Guid.NewGuid().ToString(); var result = _messagePayloadSerializer.SerializeBody(dispatch.Payload); - var message = MessageHelper.CreateMessage(result.ContentType, result.Body, registration.PayloadTypeId); + var message = MessageHelper.CreateMessage(result.ContentType, result.Body, registration.PayloadTypeId, registration.PayloadTypeIdProperty); - dispatch.ApplicationProperties.Remove(UserProperties.PayloadTypeIdProperty); + dispatch.ApplicationProperties.Remove(registration.PayloadTypeIdProperty ?? UserProperties.DefaultPayloadTypeIdProperty); foreach (var dispatchApplicationProperty in dispatch.ApplicationProperties) { message.ApplicationProperties[dispatchApplicationProperty.Key] = dispatchApplicationProperty.Value; diff --git a/src/Ev.ServiceBus/Management/Wrappers/ComposedReceiverOptions.cs b/src/Ev.ServiceBus/Management/Wrappers/ComposedReceiverOptions.cs index a7a5c3b..e80a4e5 100644 --- a/src/Ev.ServiceBus/Management/Wrappers/ComposedReceiverOptions.cs +++ b/src/Ev.ServiceBus/Management/Wrappers/ComposedReceiverOptions.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using Azure.Messaging.ServiceBus; using Ev.ServiceBus.Abstractions; @@ -16,6 +18,7 @@ public ComposedReceiverOptions(ReceiverOptions[] allOptions) SessionMode = false; ConnectionSettings = allOptions.First().ConnectionSettings; FirstOption = allOptions.First(); + PayloadTypeIdProperty = allOptions.FirstOrDefault(o => !string.IsNullOrEmpty(o.PayloadTypeIdProperty))?.PayloadTypeIdProperty; ProcessorOptions = new ServiceBusProcessorOptions(); foreach (var config in AllOptions.Select(o => o.ServiceBusProcessorOptions)) @@ -44,7 +47,8 @@ public ComposedReceiverOptions(ReceiverOptions[] allOptions) public ServiceBusProcessorOptions ProcessorOptions { get; } public ServiceBusSessionProcessorOptions? SessionProcessorOptions { get; } public ConnectionSettings? ConnectionSettings { get; } - + public string? PayloadTypeIdProperty { get; } + internal void UpdateResourceId(string resourceId) { ResourceId = resourceId; diff --git a/src/Ev.ServiceBus/Management/Wrappers/ReceiverWrapper.cs b/src/Ev.ServiceBus/Management/Wrappers/ReceiverWrapper.cs index 15d91b8..fcf9026 100644 --- a/src/Ev.ServiceBus/Management/Wrappers/ReceiverWrapper.cs +++ b/src/Ev.ServiceBus/Management/Wrappers/ReceiverWrapper.cs @@ -85,7 +85,7 @@ protected virtual async Task RegisterMessageHandler() _ => ProcessorClient }; ProcessorClient!.ProcessErrorAsync += OnExceptionOccured; - ProcessorClient.ProcessMessageAsync += args => OnMessageReceived(new MessageContext(args, _composedOptions.ClientType, _composedOptions.ResourceId)); + ProcessorClient.ProcessMessageAsync += args => OnMessageReceived(new MessageContext(args, _composedOptions.ClientType, _composedOptions.ResourceId, _composedOptions.PayloadTypeIdProperty)); await ProcessorClient.StartProcessingAsync(); _onExceptionReceivedHandler = _ => Task.CompletedTask; diff --git a/src/Ev.ServiceBus/Management/Wrappers/SessionReceiverWrapper.cs b/src/Ev.ServiceBus/Management/Wrappers/SessionReceiverWrapper.cs index 1726b37..0985073 100644 --- a/src/Ev.ServiceBus/Management/Wrappers/SessionReceiverWrapper.cs +++ b/src/Ev.ServiceBus/Management/Wrappers/SessionReceiverWrapper.cs @@ -65,7 +65,7 @@ protected override async Task RegisterMessageHandler() _ => SessionProcessorClient }; SessionProcessorClient!.ProcessErrorAsync += OnExceptionOccured; - SessionProcessorClient.ProcessMessageAsync += args => OnMessageReceived(new MessageContext(args, _composedOptions.ClientType, _composedOptions.ResourceId)); + SessionProcessorClient.ProcessMessageAsync += args => OnMessageReceived(new MessageContext(args, _composedOptions.ClientType, _composedOptions.ResourceId, _composedOptions.PayloadTypeIdProperty)); await SessionProcessorClient.StartProcessingAsync(); _onExceptionReceivedHandler = _ => Task.CompletedTask; diff --git a/src/Ev.ServiceBus/Reception/ReceptionRegistrationBuilder.cs b/src/Ev.ServiceBus/Reception/ReceptionRegistrationBuilder.cs index 637e0df..fdf99e7 100644 --- a/src/Ev.ServiceBus/Reception/ReceptionRegistrationBuilder.cs +++ b/src/Ev.ServiceBus/Reception/ReceptionRegistrationBuilder.cs @@ -94,4 +94,13 @@ public void EnableSessionHandling(Action conf { _options.EnableSessionHandling(config); } + + /// + /// Overrides the default property name for PayloadTypeId key in metadata. + /// + /// + public void WithCustomPayloadTypeIdProperty(string customPayloadTypeIdProperty) + { + _options.WithCustomPayloadTypeIdProperty(customPayloadTypeIdProperty); + } } \ No newline at end of file diff --git a/tests/Ev.ServiceBus.TestHelpers/TestMessageHelper.cs b/tests/Ev.ServiceBus.TestHelpers/TestMessageHelper.cs index 51a5058..da39722 100644 --- a/tests/Ev.ServiceBus.TestHelpers/TestMessageHelper.cs +++ b/tests/Ev.ServiceBus.TestHelpers/TestMessageHelper.cs @@ -6,11 +6,11 @@ namespace Ev.ServiceBus.TestHelpers; public static class TestMessageHelper { - public static ServiceBusMessage CreateEventMessage(string payloadTypeId, object payload) + public static ServiceBusMessage CreateEventMessage(string payloadTypeId, object payload, string payloadTypeIdProperty = UserProperties.DefaultPayloadTypeIdProperty) { var parser = new TextJsonPayloadSerializer(); var result = parser.SerializeBody(payload); - var message = MessageHelper.CreateMessage(result.ContentType, result.Body, payloadTypeId); + var message = MessageHelper.CreateMessage(result.ContentType, result.Body, payloadTypeId, payloadTypeIdProperty); return message; } diff --git a/tests/Ev.ServiceBus.UnitTests/DispatchTest.cs b/tests/Ev.ServiceBus.UnitTests/DispatchTest.cs index 245fdbb..eff68cb 100644 --- a/tests/Ev.ServiceBus.UnitTests/DispatchTest.cs +++ b/tests/Ev.ServiceBus.UnitTests/DispatchTest.cs @@ -23,9 +23,12 @@ namespace Ev.ServiceBus.UnitTests; public class DispatchTest : IDisposable { + private const string CustomPayloadTypeIdProperty = "customized-property"; private readonly Composer _composer; private readonly List _sentMessagesToTopic; private readonly List _sentMessagesToQueue; + private readonly List _sentMessagesToTopicCustomProperty; + private readonly List _sentMessagesToQueueCustomProperty; private readonly List _sentMessagesToQueueSession; public DispatchTest() @@ -37,6 +40,8 @@ public DispatchTest() _sentMessagesToTopic = new List(); _sentMessagesToQueue = new List(); + _sentMessagesToTopicCustomProperty = new List(); + _sentMessagesToQueueCustomProperty = new List(); _sentMessagesToQueueSession = new List(); _composer = new Composer(); @@ -44,19 +49,33 @@ public DispatchTest() { services.RegisterServiceBusDispatch().ToTopic("testTopic", builder => { - builder.RegisterDispatch().CustomizePayloadTypeId("MyEvent"); + builder.RegisterDispatch() + .CustomizePayloadTypeId("MyEvent"); // noise builder.RegisterDispatch().CustomizePayloadTypeId("MyEvent3"); }); + services.RegisterServiceBusDispatch().ToTopic("testTopicCustomProperty", builder => + { + builder.RegisterDispatch() + .CustomizePayloadTypeId("MyEventCustomProperty") + .CustomizePayloadTypeIdProperty(CustomPayloadTypeIdProperty); + }); services.RegisterServiceBusDispatch().ToQueue("testQueue", builder => { - builder.RegisterDispatch().CustomizePayloadTypeId("MyEventThroughQueue"); + builder.RegisterDispatch() + .CustomizePayloadTypeId("MyEventThroughQueue"); + }); + services.RegisterServiceBusDispatch().ToQueue("testQueueCustomProperty", builder => + { + builder.RegisterDispatch() + .CustomizePayloadTypeId("MyEventThroughQueueWithCustomProperty") + .CustomizePayloadTypeIdProperty(CustomPayloadTypeIdProperty); }); - services.RegisterServiceBusDispatch().ToQueue("testQueueSession", builder => { - builder.RegisterDispatch().CustomizePayloadTypeId("MyEventThroughQueue"); + builder.RegisterDispatch() + .CustomizePayloadTypeId("MyEventThroughQueue"); }); // noise @@ -84,10 +103,20 @@ public DispatchTest() { _sentMessagesToTopic.Add(message); }); - topicClient.Mock.Setup(o => o.CreateMessageBatchAsync(It.IsAny())) .ReturnsAsync(ServiceBusModelFactory.ServiceBusMessageBatch(0, _sentMessagesToTopic, createMessageBatchOptions)); + var topicClientCustomProperty = _composer.ClientFactory.GetSenderMock("testTopicCustomProperty"); + topicClientCustomProperty.Mock + .Setup(o => o.SendMessageAsync(It.IsAny(), It.IsAny())) + .Returns(Task.CompletedTask) + .Callback((ServiceBusMessage message, CancellationToken token) => + { + _sentMessagesToTopicCustomProperty.Add(message); + }); + topicClientCustomProperty.Mock.Setup(o => o.CreateMessageBatchAsync(It.IsAny())) + .ReturnsAsync(ServiceBusModelFactory.ServiceBusMessageBatch(0, _sentMessagesToTopicCustomProperty, createMessageBatchOptions)); + var queueClient = _composer.ClientFactory.GetSenderMock("testQueue"); queueClient.Mock .Setup(o => o.SendMessageAsync(It.IsAny(), It.IsAny())) @@ -99,6 +128,17 @@ public DispatchTest() queueClient.Mock.Setup(o => o.CreateMessageBatchAsync(It.IsAny())) .ReturnsAsync(ServiceBusModelFactory.ServiceBusMessageBatch(0, _sentMessagesToQueue, createMessageBatchOptions)); + var queueClientCustomProperty = _composer.ClientFactory.GetSenderMock("testQueueCustomProperty"); + queueClient.Mock + .Setup(o => o.SendMessageAsync(It.IsAny(), It.IsAny())) + .Returns(Task.CompletedTask) + .Callback((ServiceBusMessage message, CancellationToken token) => + { + _sentMessagesToQueueCustomProperty.Add(message); + }); + queueClientCustomProperty.Mock.Setup(o => o.CreateMessageBatchAsync(It.IsAny())) + .ReturnsAsync(ServiceBusModelFactory.ServiceBusMessageBatch(0, _sentMessagesToQueueCustomProperty, createMessageBatchOptions)); + var queueClientSession = _composer.ClientFactory.GetSenderMock("testQueueSession"); queueClientSession.Mock .Setup(o => o.SendMessageAsync(It.IsAny(), It.IsAny())) @@ -171,13 +211,15 @@ public void MessageMustContainTheRightMessageType(string clientToCheck) } [Theory] - [InlineData("topic", "MyEvent")] - [InlineData("queue", "MyEventThroughQueue")] - public void MessageMustContainTheRightPayloadTypeId(string clientToCheck, string payloadTypeId) + [InlineData("topic", "MyEvent", UserProperties.DefaultPayloadTypeIdProperty)] + [InlineData("queue", "MyEventThroughQueue", UserProperties.DefaultPayloadTypeIdProperty)] + [InlineData("topic2", "MyEventCustomProperty", CustomPayloadTypeIdProperty)] + [InlineData("queue2", "MyEventThroughQueueWithCustomProperty", CustomPayloadTypeIdProperty)] + public void MessageMustContainTheRightPayloadTypeIdInTheRightProperty(string clientToCheck, string payloadTypeId, string payloadTypeIdProperty) { var message = GetMessageFrom(clientToCheck); - Assert.True(message?.ApplicationProperties.ContainsKey("PayloadTypeId")); - Assert.Equal(payloadTypeId, message?.ApplicationProperties["PayloadTypeId"]); + Assert.True(message?.ApplicationProperties.ContainsKey(payloadTypeIdProperty)); + Assert.Equal(payloadTypeId, message?.ApplicationProperties[payloadTypeIdProperty]); } [Theory] @@ -531,11 +573,20 @@ private ServiceBusMessage GetMessageFrom(string clientToCheck) { return _sentMessagesToTopic.FirstOrDefault(); } - if (clientToCheck == "sessionQueue") + if (clientToCheck == "topic2") + { + return _sentMessagesToTopicCustomProperty.FirstOrDefault(); + } + if (clientToCheck == "queue") + { + return _sentMessagesToQueue.FirstOrDefault(); + } + if (clientToCheck == "queue2") { - return _sentMessagesToQueueSession.FirstOrDefault(); + return _sentMessagesToQueueCustomProperty.FirstOrDefault(); } - return _sentMessagesToQueue.FirstOrDefault(); + // sessionQueue + return _sentMessagesToQueueSession.FirstOrDefault(); } public void Dispose() diff --git a/tests/Ev.ServiceBus.UnitTests/EventListenerTests.cs b/tests/Ev.ServiceBus.UnitTests/EventListenerTests.cs index 07dbde0..231a154 100644 --- a/tests/Ev.ServiceBus.UnitTests/EventListenerTests.cs +++ b/tests/Ev.ServiceBus.UnitTests/EventListenerTests.cs @@ -14,8 +14,10 @@ namespace Ev.ServiceBus.UnitTests; public class EventListenerTests { - [Fact] - public async Task CanListenToQueueEvents() + [Theory] + [InlineData(null)] + [InlineData("customPropertyName")] + public async Task CanListenToQueueEvents(string customPropertyName) { var mock = new Mock(); var composer = new Composer(); @@ -31,6 +33,7 @@ public async Task CanListenToQueueEvents() services.RegisterServiceBusReception().FromQueue("testQueue", builder => { builder.RegisterReception(); + builder.WithCustomPayloadTypeIdProperty(customPropertyName); }); }); @@ -38,7 +41,7 @@ public async Task CanListenToQueueEvents() var clientMock = composer.Provider.GetProcessorMock("testQueue"); var result = composer.Provider.GetRequiredService().SerializeBody(new SubscribedEvent()); - var message = MessageHelper.CreateMessage(result.ContentType, result.Body, nameof(SubscribedEvent)); + var message = MessageHelper.CreateMessage(result.ContentType, result.Body, nameof(SubscribedEvent), customPropertyName); await clientMock.TriggerMessageReception(message, CancellationToken.None); @@ -71,7 +74,7 @@ public async Task CanListenToQueueEventsWhenThrowingExceptions() var clientMock = composer.Provider.GetProcessorMock("testQueue"); var result = composer.Provider.GetRequiredService().SerializeBody(new SubscribedEvent()); - var message = MessageHelper.CreateMessage(result.ContentType, result.Body, nameof(SubscribedEvent)); + var message = MessageHelper.CreateMessage(result.ContentType, result.Body, nameof(SubscribedEvent), null); message.MessageId = Guid.NewGuid().ToString(); var action = async () => @@ -119,7 +122,7 @@ public async Task CanListenToSubscriptionEvents() var clientMock = composer.Provider.GetProcessorMock("testTopic", "testSubscription"); var result = composer.Provider.GetRequiredService().SerializeBody(new SubscribedEvent()); - var message = MessageHelper.CreateMessage(result.ContentType, result.Body, nameof(SubscribedEvent)); + var message = MessageHelper.CreateMessage(result.ContentType, result.Body, nameof(SubscribedEvent), null); await clientMock.TriggerMessageReception(message, CancellationToken.None); @@ -152,7 +155,7 @@ public async Task CanListenToSubscriptionEventsWhenThrowingExceptions() var clientMock = composer.Provider.GetProcessorMock("testTopic", "testSubscription"); var result = composer.Provider.GetRequiredService().SerializeBody(new SubscribedEvent()); - var message = MessageHelper.CreateMessage(result.ContentType, result.Body, nameof(SubscribedEvent)); + var message = MessageHelper.CreateMessage(result.ContentType, result.Body, nameof(SubscribedEvent), null); message.MessageId = Guid.NewGuid().ToString(); var action = async () => diff --git a/tests/Ev.ServiceBus.UnitTests/MessageMetadataTests.cs b/tests/Ev.ServiceBus.UnitTests/MessageMetadataTests.cs index 4f5ff7f..730395e 100644 --- a/tests/Ev.ServiceBus.UnitTests/MessageMetadataTests.cs +++ b/tests/Ev.ServiceBus.UnitTests/MessageMetadataTests.cs @@ -15,8 +15,10 @@ namespace Ev.ServiceBus.UnitTests; public class MessageMetadataTests { - [Fact] - public async Task MetadataIsProperlySet() + [Theory] + [InlineData(null)] + [InlineData("CustomPayloadTypeIdProperty")] + public async Task MetadataIsProperlySet(string customPropertyName) { var composer = new Composer(); @@ -27,6 +29,7 @@ public async Task MetadataIsProperlySet() services.RegisterServiceBusReception().FromQueue("testQueue", builder => { builder.RegisterReception(); + builder.WithCustomPayloadTypeIdProperty(customPropertyName); }); }); @@ -34,7 +37,7 @@ public async Task MetadataIsProperlySet() var clientMock = provider.GetProcessorMock("testQueue"); - await SimulateEventReception(clientMock); + await SimulateEventReception(clientMock, customPayloadTypeIdPropertyName: customPropertyName); var metadatas = provider.GetRequiredService>(); metadatas.Count.Should().Be(1); @@ -45,7 +48,7 @@ public async Task MetadataIsProperlySet() metadata.ApplicationProperties.Keys.Should() .Contain(UserProperties.MessageTypeProperty) .And - .Contain(UserProperties.PayloadTypeIdProperty); + .Contain(customPropertyName ?? UserProperties.DefaultPayloadTypeIdProperty); metadata.CorrelationId.Should().Be("8B4C4C3C-482A-4688-8458-AFF9998C0A12"); metadata.SessionId.Should().Be("ABB8761B-C22E-407E-801C-DFAF68916F04"); } @@ -116,7 +119,8 @@ public async Task MessageManagementMethodsAreCalledForSession() private async Task SimulateEventReception( ProcessorMock client, CancellationToken? cancellationToken = null, - ServiceBusReceiver receiver = null) + ServiceBusReceiver receiver = null, + string customPayloadTypeIdPropertyName = null) { var parser = new TextJsonPayloadSerializer(); var result = parser.SerializeBody(new { }); @@ -127,7 +131,7 @@ private async Task SimulateEventReception( ApplicationProperties = { { UserProperties.MessageTypeProperty, "IntegrationEvent" }, - { UserProperties.PayloadTypeIdProperty, "Payload" } + { customPayloadTypeIdPropertyName ?? UserProperties.DefaultPayloadTypeIdProperty, "Payload" } }, CorrelationId = "8B4C4C3C-482A-4688-8458-AFF9998C0A12", SessionId = "ABB8761B-C22E-407E-801C-DFAF68916F04" @@ -155,7 +159,7 @@ private async Task SimulateSessionEventReception( ApplicationProperties = { { UserProperties.MessageTypeProperty, "IntegrationEvent" }, - { UserProperties.PayloadTypeIdProperty, "Payload" } + { UserProperties.DefaultPayloadTypeIdProperty, "Payload" } }, CorrelationId = "8B4C4C3C-482A-4688-8458-AFF9998C0A12", SessionId = "ABB8761B-C22E-407E-801C-DFAF68916F04" diff --git a/tests/Ev.ServiceBus.UnitTests/ReceptionTest.cs b/tests/Ev.ServiceBus.UnitTests/ReceptionTest.cs index d24a0ac..13f948e 100644 --- a/tests/Ev.ServiceBus.UnitTests/ReceptionTest.cs +++ b/tests/Ev.ServiceBus.UnitTests/ReceptionTest.cs @@ -309,7 +309,7 @@ private async Task SimulateEventReception( ApplicationProperties = { { UserProperties.MessageTypeProperty, "IntegrationEvent" }, - { UserProperties.PayloadTypeIdProperty, "MyEvent" } + { UserProperties.DefaultPayloadTypeIdProperty, "MyEvent" } } }; From f4ae782dd1a3641f37fab598c74a44e85dc69d4d Mon Sep 17 00:00:00 2001 From: Fermin Saez Date: Fri, 14 Mar 2025 17:29:29 +0100 Subject: [PATCH 2/2] chore: add changelog and update documentation. --- README.md | 2 +- docs/AdvancedScenarios.md | 26 ++++++++++++++++++++++++++ docs/CHANGELOG.md | 6 ++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a6901f4..ace065e 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ The nuget will take care of deserializing the message into proper object and giv This whole process revolves around the ability to differentiate messages by their payload types. To do that, it adds a UserProperty to every message. This property is the unique identifier for a designated contract -across the whole system (name of the property : `PayloadTypeId`). +across the whole system (name of the property : `PayloadTypeId`, if you need to use another property name, please see *Customizing the PayloadTypeId property name* in [Advanced Scenarios](./docs/AdvancedScenarios.md)). > Be careful when you have a system with several applications. If several applications send 2 different contracts > with the same Id to a single queue/topic, the receiving handlers will not be able to differentiate between them. diff --git a/docs/AdvancedScenarios.md b/docs/AdvancedScenarios.md index 6ba9aec..07cb1c5 100644 --- a/docs/AdvancedScenarios.md +++ b/docs/AdvancedScenarios.md @@ -201,3 +201,29 @@ public class MyMessageSender } } ``` + + +## Customizing the PayloadTypeId property name + +This package uses a UserProperty attached to every message in order to differentiate them by their payload type. +This property is the unique identifier for a designated contract across the whole system. +The name of the property that holds the contract name is *PayloadTypeId* by default, but there are cases where you want to change that property name. +To send messages with a different property name you need to configure it in the receiver: + +```csharp +services.RegisterServiceBusReception().FromQueue("myQueue", builder => + { + builder.RegisterReception(); + builder.WithCustomPayloadTypeIdProperty("DifferentPayloadTypeIdPropertyName"); + }); +``` + +To receive messages with a different property name you need to configure it in the sender: + +```csharp +services.RegisterServiceBusDispatch().ToQueue("myQueue", builder => + { + builder.RegisterDispatch() + .CustomizePayloadTypeIdProperty("DifferentPayloadTypeIdPropertyName"); + }); +``` diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 4e57131..a8cd10e 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 5.3.0 +- Added + - Introduced *CustomizePayloadTypeIdProperty* method so we can customize the *PayloadTypeId* property name when sending to a topic or queue + - Introduced *WithCustomPayloadTypeIdProperty* method so we can customize the *PayloadTypeId* property name when receiving messages + ## 5.2.0 - Added - Introduced SendDispatch methods on DispatchSender. Those methods allow to send single message bigger than 1MB