Skip to content

Commit 2bc86b2

Browse files
committed
Parse data as the actual json object
1 parent e735bbf commit 2bc86b2

File tree

9 files changed

+115
-47
lines changed

9 files changed

+115
-47
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"Projects": [
3+
{
4+
"Name": "AWS.Messaging",
5+
"Type": "Minor",
6+
"ChangelogMessages": [
7+
"Update MessageSerializer to store data as actual json. Fixes #168"
8+
]
9+
}
10+
]
11+
}

src/AWS.Messaging/MessageEnvelope.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ public abstract class MessageEnvelope
4444
[JsonPropertyName("time")]
4545
public DateTimeOffset TimeStamp { get; set; } = DateTimeOffset.MinValue;
4646

47+
/// <summary>
48+
/// The data content type.
49+
/// </summary>
50+
[JsonPropertyName("datacontenttype")]
51+
public string? DataContentType { get; set; }
52+
4753
/// <summary>
4854
/// This stores different metadata that is not modeled as a top-level property in MessageEnvelope class.
4955
/// These entries will also be serialized as top-level properties when sending the message, which

src/AWS.Messaging/Serialization/EnvelopeSerializer.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
using System.Text;
54
using System.Text.Json;
65
using System.Text.Json.Nodes;
76
using Amazon.SQS.Model;
87
using AWS.Messaging.Configuration;
9-
using AWS.Messaging.Internal;
108
using AWS.Messaging.Serialization.Helpers;
9+
using AWS.Messaging.Internal;
1110
using AWS.Messaging.Services;
1211
using Microsoft.Extensions.Logging;
1312
using AWS.Messaging.Serialization.Parsers;
@@ -104,7 +103,8 @@ public async ValueTask<string> SerializeAsync<T>(MessageEnvelope<T> envelope)
104103
["specversion"] = envelope.Version,
105104
["type"] = envelope.MessageTypeIdentifier,
106105
["time"] = envelope.TimeStamp,
107-
["data"] = _messageSerializer.Serialize(message)
106+
["datacontenttype"] = _messageSerializer.DataContentType,
107+
["data"] = JsonNode.Parse(_messageSerializer.Serialize(message)) // parse the string to get the value as the actual json node.
108108
};
109109

110110
// Write any Metadata as top-level keys
@@ -204,6 +204,7 @@ public async ValueTask<ConvertToEnvelopeResult> ConvertToEnvelopeAsync(Message s
204204
envelope.Version = JsonPropertyHelper.GetRequiredProperty(root, "specversion", element => element.GetString()!);
205205
envelope.MessageTypeIdentifier = JsonPropertyHelper.GetRequiredProperty(root, "type", element => element.GetString()!);
206206
envelope.TimeStamp = JsonPropertyHelper.GetRequiredProperty(root, "time", element => element.GetDateTimeOffset());
207+
envelope.DataContentType = JsonPropertyHelper.GetStringProperty(root, "datacontenttype");
207208

208209
// Handle metadata - copy any properties that aren't standard envelope properties
209210
foreach (var property in root.EnumerateObject())
@@ -215,7 +216,7 @@ public async ValueTask<ConvertToEnvelopeResult> ConvertToEnvelopeAsync(Message s
215216
}
216217

217218
// Deserialize the message content using the custom serializer
218-
var dataContent = JsonPropertyHelper.GetRequiredProperty(root, "data", element => element.GetString()!);
219+
var dataContent = JsonPropertyHelper.GetRequiredProperty(root, "data", element => element.GetRawText());
219220
var message = _messageSerializer.Deserialize(dataContent, subscriberMapping.MessageType);
220221
envelope.SetMessage(message);
221222

src/AWS.Messaging/Serialization/IMessageSerializer.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,9 @@ T Deserialize<T>(string message)
3030
{
3131
return (T)Deserialize(message, typeof(T));
3232
}
33+
34+
/// <summary>
35+
/// The data content type
36+
/// </summary>
37+
string DataContentType { get; }
3338
}

src/AWS.Messaging/Serialization/MessageSerializer.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,9 @@ public string Serialize(object message)
113113
throw new FailedToSerializeApplicationMessageException("Failed to serialize application message into a string", ex);
114114
}
115115
}
116+
117+
/// <summary>
118+
/// The data content type
119+
/// </summary>
120+
public string DataContentType => "application/json";
116121
}

test/AWS.Messaging.IntegrationTests/EventBridgePublisherTests.cs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
using Amazon.SQS.Model;
1313
using Amazon.SecurityToken;
1414
using Amazon.SecurityToken.Model;
15+
using AWS.Messaging.IntegrationTests.Handlers;
16+
using AWS.Messaging.Serialization;
1517

1618
namespace AWS.Messaging.IntegrationTests;
1719

@@ -105,6 +107,7 @@ await _eventBridgeClient.PutTargetsAsync(new PutTargetsRequest
105107
{
106108
builder.AddEventBridgePublisher<ChatMessage>(_eventBusArn);
107109
builder.AddMessageSource("/aws/messaging");
110+
builder.AddMessageHandler<ChatMessageHandler, ChatMessage>();
108111
});
109112
_serviceProvider = serviceCollection.BuildServiceProvider();
110113
}
@@ -126,23 +129,23 @@ await publisher.PublishAsync(new ChatMessage
126129
var receiveMessageResponse = await _sqsClient.ReceiveMessageAsync(_sqsQueueUrl);
127130
var message = Assert.Single(receiveMessageResponse.Messages);
128131

129-
// EventBridge adds an external envelope which we need to strip away
130-
var eventBridgeEnvelope = JsonSerializer.Deserialize<EventBridgeEnvelope>(message.Body);
131-
Assert.NotNull(eventBridgeEnvelope);
132+
var envelopeSerializer = _serviceProvider.GetRequiredService<IEnvelopeSerializer>();
132133

133-
Assert.NotNull(eventBridgeEnvelope.Detail);
134-
var envelope = eventBridgeEnvelope.Detail;
134+
// Use the EnvelopeSerializer to convert the message
135+
var result = await envelopeSerializer.ConvertToEnvelopeAsync(message);
136+
var envelope = result.Envelope as MessageEnvelope<ChatMessage>;
137+
138+
Assert.NotNull(envelope);
135139
Assert.False(string.IsNullOrEmpty(envelope.Id));
136140
Assert.Equal("/aws/messaging", envelope.Source.ToString());
137141
Assert.True(envelope.TimeStamp > publishStartTime);
138142
Assert.True(envelope.TimeStamp < publishEndTime);
143+
Assert.Equal(typeof(ChatMessage).ToString(), envelope.MessageTypeIdentifier);
139144

140-
var messageType = Type.GetType(eventBridgeEnvelope.Detail.MessageTypeIdentifier);
141-
Assert.NotNull(messageType);
142-
143-
var chatMessageObject = JsonSerializer.Deserialize(eventBridgeEnvelope.Detail.Message, messageType);
144-
var chatMessage = Assert.IsType<ChatMessage>(chatMessageObject);
145-
Assert.Equal("Test1", chatMessage.MessageDescription);
145+
var chatMessage = envelope.Message;
146+
Assert.NotNull(chatMessage);
147+
Assert.IsType<ChatMessage>(chatMessage);
148+
Assert.Equal("Test1", chatMessage.MessageDescription);;
146149
}
147150

148151
public async Task DisposeAsync()

test/AWS.Messaging.IntegrationTests/SNSPublisherTests.cs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
using System.Text.Json;
99
using Amazon.SimpleNotificationService;
1010
using Amazon.SimpleNotificationService.Model;
11+
using AWS.Messaging.IntegrationTests.Handlers;
12+
using AWS.Messaging.Serialization;
1113

1214
namespace AWS.Messaging.IntegrationTests;
1315

@@ -45,6 +47,7 @@ public async Task InitializeAsync()
4547
{
4648
builder.AddSNSPublisher<ChatMessage>(_snsTopicArn);
4749
builder.AddMessageSource("/aws/messaging");
50+
builder.AddMessageHandler<ChatMessageHandler, ChatMessage>();
4851
});
4952
_serviceProvider = serviceCollection.BuildServiceProvider();
5053
}
@@ -70,18 +73,23 @@ await publisher.PublishAsync(new ChatMessage
7073
var snsEnvelope = JsonSerializer.Deserialize<SNSEnvelope>(message.Body);
7174
Assert.NotNull(snsEnvelope);
7275

73-
var envelope = JsonSerializer.Deserialize<MessageEnvelope<string>>(snsEnvelope.Message);
76+
// Get the EnvelopeSerializer from the service provider
77+
var envelopeSerializer = _serviceProvider.GetRequiredService<IEnvelopeSerializer>();
78+
79+
// Use the EnvelopeSerializer to convert the message
80+
var result = await envelopeSerializer.ConvertToEnvelopeAsync(message);
81+
var envelope = result.Envelope as MessageEnvelope<ChatMessage>;
82+
7483
Assert.NotNull(envelope);
7584
Assert.False(string.IsNullOrEmpty(envelope.Id));
7685
Assert.Equal("/aws/messaging", envelope.Source.ToString());
7786
Assert.True(envelope.TimeStamp > publishStartTime);
7887
Assert.True(envelope.TimeStamp < publishEndTime);
88+
Assert.Equal(typeof(ChatMessage).ToString(), envelope.MessageTypeIdentifier);
7989

80-
var messageType = Type.GetType(envelope.MessageTypeIdentifier);
81-
Assert.NotNull(messageType);
82-
83-
var chatMessageObject = JsonSerializer.Deserialize(envelope.Message, messageType);
84-
var chatMessage = Assert.IsType<ChatMessage>(chatMessageObject);
90+
var chatMessage = envelope.Message;
91+
Assert.NotNull(chatMessage);
92+
Assert.IsType<ChatMessage>(chatMessage);
8593
Assert.Equal("Test1", chatMessage.MessageDescription);
8694
}
8795

test/AWS.Messaging.IntegrationTests/SQSPublisherTests.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
using Microsoft.Extensions.DependencyInjection;
77
using AWS.Messaging.IntegrationTests.Models;
88
using System.Text.Json;
9+
using AWS.Messaging.IntegrationTests.Handlers;
10+
using AWS.Messaging.Serialization;
911

1012
namespace AWS.Messaging.IntegrationTests;
1113

@@ -33,6 +35,8 @@ public async Task InitializeAsync()
3335
{
3436
builder.AddSQSPublisher<ChatMessage>(_sqsQueueUrl);
3537
builder.AddMessageSource("/aws/messaging");
38+
builder.AddMessageHandler<ChatMessageHandler, ChatMessage>();
39+
3640
});
3741
_serviceProvider = serviceCollection.BuildServiceProvider();
3842
}
@@ -54,19 +58,27 @@ await publisher.PublishAsync(new ChatMessage
5458
var receiveMessageResponse = await _sqsClient.ReceiveMessageAsync(_sqsQueueUrl);
5559
var message = Assert.Single(receiveMessageResponse.Messages);
5660

57-
var envelope = JsonSerializer.Deserialize<MessageEnvelope<string>>(message.Body);
61+
// Get the EnvelopeSerializer from the service provider
62+
var envelopeSerializer = _serviceProvider.GetRequiredService<IEnvelopeSerializer>();
63+
64+
// Use the EnvelopeSerializer to convert the message
65+
var result = await envelopeSerializer.ConvertToEnvelopeAsync(message);
66+
var envelope = result.Envelope as MessageEnvelope<ChatMessage>;
67+
5868
Assert.NotNull(envelope);
5969
Assert.False(string.IsNullOrEmpty(envelope.Id));
6070
Assert.Equal("/aws/messaging", envelope.Source.ToString());
61-
Assert.True(envelope.TimeStamp > publishStartTime);
71+
Assert.True(envelope.TimeStamp > publishStartTime);
6272
Assert.True(envelope.TimeStamp < publishEndTime);
63-
var messageType = Type.GetType(envelope.MessageTypeIdentifier);
64-
Assert.NotNull(messageType);
65-
var chatMessageObject = JsonSerializer.Deserialize(envelope.Message, messageType);
66-
var chatMessage = Assert.IsType<ChatMessage>(chatMessageObject);
73+
Assert.Equal(typeof(ChatMessage).ToString(), envelope.MessageTypeIdentifier);
74+
75+
var chatMessage = envelope.Message;
76+
Assert.NotNull(chatMessage);
77+
Assert.IsType<ChatMessage>(chatMessage);
6778
Assert.Equal("Test1", chatMessage.MessageDescription);
6879
}
6980

81+
7082
public async Task DisposeAsync()
7183
{
7284
try

test/AWS.Messaging.UnitTests/SerializationTests/EnvelopeSerializerTests.cs

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public async Task SerializeEnvelope()
119119

120120
// ASSERT
121121
// The \u0022 corresponds to quotation mark (")
122-
var expectedBlob = "{\"id\":\"id-123\",\"source\":\"/backend/service\",\"specversion\":\"1.0\",\"type\":\"addressInfo\",\"time\":\"2000-12-05T10:30:55+00:00\",\"data\":\"{\\u0022Unit\\u0022:123,\\u0022Street\\u0022:\\u0022Prince St\\u0022,\\u0022ZipCode\\u0022:\\u002200001\\u0022}\"}";
122+
var expectedBlob = "{\"id\":\"id-123\",\"source\":\"/backend/service\",\"specversion\":\"1.0\",\"type\":\"addressInfo\",\"time\":\"2000-12-05T10:30:55+00:00\",\"datacontenttype\":\"application/json\",\"data\":{\"Unit\":123,\"Street\":\"Prince St\",\"ZipCode\":\"00001\"}}";
123123
Assert.Equal(expectedBlob, jsonBlob);
124124
}
125125

@@ -272,19 +272,19 @@ public async Task ConvertToEnvelope_With_EventBridgeOuterEnvelope_In_SQSMessageB
272272
var serviceProvider = _serviceCollection.BuildServiceProvider();
273273
var envelopeSerializer = serviceProvider.GetRequiredService<IEnvelopeSerializer>();
274274

275-
var innerMessageEnvelope = new MessageEnvelope<string>
275+
var innerMessageEnvelope = new MessageEnvelope<AddressInfo>
276276
{
277277
Id = "66659d05-e4ff-462f-81c4-09e560e66a5c",
278278
Source = new Uri("/aws/messaging", UriKind.Relative),
279279
Version = "1.0",
280280
MessageTypeIdentifier = "addressInfo",
281281
TimeStamp = _testdate,
282-
Message = JsonSerializer.Serialize(new AddressInfo
282+
Message = new AddressInfo
283283
{
284284
Street = "Prince St",
285285
Unit = 123,
286286
ZipCode = "00001"
287-
})
287+
}
288288
};
289289

290290
var outerMessageEnvelope = new Dictionary<string, object>
@@ -397,7 +397,7 @@ public async Task SerializationCallbacks_AreCorrectlyInvoked()
397397
var serializedMessage = await envelopeSerializer.SerializeAsync(messageEnvelope);
398398

399399
// ASSERT - Check expected base 64 encoded string
400-
var expectedserializedMessage = "eyJpZCI6IjEyMyIsInNvdXJjZSI6Ii9hd3MvbWVzc2FnaW5nIiwic3BlY3ZlcnNpb24iOiIxLjAiLCJ0eXBlIjoiYWRkcmVzc0luZm8iLCJ0aW1lIjoiMjAwMC0xMi0wNVQxMDozMDo1NSswMDowMCIsImRhdGEiOiJ7XHUwMDIyVW5pdFx1MDAyMjoxMjMsXHUwMDIyU3RyZWV0XHUwMDIyOlx1MDAyMlByaW5jZSBTdFx1MDAyMixcdTAwMjJaaXBDb2RlXHUwMDIyOlx1MDAyMjAwMDAxXHUwMDIyfSIsIklzLURlbGl2ZXJlZCI6ZmFsc2V9";
400+
var expectedserializedMessage = "eyJpZCI6IjEyMyIsInNvdXJjZSI6Ii9hd3MvbWVzc2FnaW5nIiwic3BlY3ZlcnNpb24iOiIxLjAiLCJ0eXBlIjoiYWRkcmVzc0luZm8iLCJ0aW1lIjoiMjAwMC0xMi0wNVQxMDozMDo1NSswMDowMCIsImRhdGFjb250ZW50dHlwZSI6ImFwcGxpY2F0aW9uL2pzb24iLCJkYXRhIjp7IlVuaXQiOjEyMywiU3RyZWV0IjoiUHJpbmNlIFN0IiwiWmlwQ29kZSI6IjAwMDAxIn0sIklzLURlbGl2ZXJlZCI6ZmFsc2V9";
401401
Assert.Equal(expectedserializedMessage, serializedMessage);
402402

403403
// ACT - Convert To Envelope from base 64 Encoded Message
@@ -452,14 +452,23 @@ public async Task SerializeAsync_DataMessageLogging_NoError(bool dataMessageLogg
452452
}
453453
};
454454

455+
var serializedContent = JsonSerializer.Serialize(messageEnvelope.Message);
456+
457+
// Mock the serializer to return a specific string
458+
messageSerializer
459+
.Setup(x => x.Serialize(It.IsAny<object>()))
460+
.Returns(serializedContent);
461+
messageSerializer.Setup(x => x.DataContentType).Returns("application/json");
462+
463+
455464
await envelopeSerializer.SerializeAsync(messageEnvelope);
456465

457466
if (dataMessageLogging)
458467
{
459468
logger.Verify(log => log.Log(
460469
It.Is<LogLevel>(logLevel => logLevel == LogLevel.Trace),
461470
It.Is<EventId>(eventId => eventId.Id == 0),
462-
It.Is<It.IsAnyType>((@object, @type) => @object.ToString() == "Serialized the MessageEnvelope object as the following raw string:\n{\"id\":\"123\",\"source\":\"/aws/messaging\",\"specversion\":\"1.0\",\"type\":\"addressInfo\",\"time\":\"2000-12-05T10:30:55+00:00\",\"data\":null}"),
471+
It.Is<It.IsAnyType>((@object, @type) => @object.ToString() == "Serialized the MessageEnvelope object as the following raw string:\n{\"id\":\"123\",\"source\":\"/aws/messaging\",\"specversion\":\"1.0\",\"type\":\"addressInfo\",\"time\":\"2000-12-05T10:30:55+00:00\",\"datacontenttype\":\"application/json\",\"data\":{\"Unit\":123,\"Street\":\"Prince St\",\"ZipCode\":\"00001\"}}"),
463472
null,
464473
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
465474
Times.Once);
@@ -612,22 +621,30 @@ public async Task ConvertToEnvelope_WithMetadata_PreservesOnlyExpectedMetadataPr
612621
var envelopeSerializer = serviceProvider.GetRequiredService<IEnvelopeSerializer>();
613622

614623
// Create a JSON string with both standard envelope properties and custom metadata
615-
var jsonString = @"{
616-
""id"": ""test-id-123"",
617-
""source"": ""/aws/messaging"",
618-
""specversion"": ""1.0"",
619-
""type"": ""addressInfo"",
620-
""time"": ""2000-12-05T10:30:55+00:00"",
621-
""data"": ""{\""Unit\"":123,\""Street\"":\""Prince St\"",\""ZipCode\"":\""00001\""}"",
622-
""customString"": ""test-value"",
623-
""customNumber"": 42,
624-
""customBoolean"": true,
625-
""customObject"": {""nestedKey"": ""nestedValue""}
626-
}";
624+
var testData = new
625+
{
626+
id = "test-id-123",
627+
source = "/aws/messaging",
628+
specversion = "1.0",
629+
type = "addressInfo",
630+
time = "2000-12-05T10:30:55+00:00",
631+
data = new AddressInfo
632+
{
633+
Unit = 123,
634+
Street = "Prince St",
635+
ZipCode = "10010"
636+
},
637+
customString = "test-value",
638+
customNumber = 42,
639+
customBoolean = true,
640+
customObject = new { nestedKey = "nestedValue" }
641+
};
642+
643+
var json = JsonSerializer.Serialize(testData);
627644

628645
var sqsMessage = new Message
629646
{
630-
Body = jsonString
647+
Body = json
631648
};
632649

633650
// ACT
@@ -674,7 +691,7 @@ public async Task ConvertToEnvelope_WithMetadata_PreservesOnlyExpectedMetadataPr
674691
Assert.NotNull(deserializedEnvelope.Message);
675692
Assert.Equal("Prince St", deserializedEnvelope.Message.Street);
676693
Assert.Equal(123, deserializedEnvelope.Message.Unit);
677-
Assert.Equal("00001", deserializedEnvelope.Message.ZipCode);
694+
Assert.Equal("10010", deserializedEnvelope.Message.ZipCode);
678695
}
679696

680697
[Fact]

0 commit comments

Comments
 (0)