Skip to content

Commit

Permalink
Add System.Text.Json converter for EventGridEvent (#22295)
Browse files Browse the repository at this point in the history
* Add System.Text.Json converter for EventGridEvent

* Usings

* Fix docs

* Use more efficient parse
  • Loading branch information
JoshLove-msft authored Jun 29, 2021
1 parent 182e2b7 commit f15ec78
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@

using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using Azure.Core;
using Azure.Messaging.EventGrid.Models;

namespace Azure.Messaging.EventGrid
{
/// <summary> Properties of an event published to an Event Grid topic using the EventGrid Schema. </summary>
[JsonConverter(typeof(EventGridEventConverter))]
public class EventGridEvent
{
/// <summary> Initializes a new instance of <see cref="EventGridEvent"/>. </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using Azure.Core;
using Azure.Messaging.EventGrid.Models;

namespace Azure.Messaging.EventGrid
{
/// <summary>
/// A custom converter that attributes the <see cref="EventGridEvent"/> type.
/// This allows System.Text.Json to serialize and deserialize EventGridEvent by default.
/// </summary>
internal class EventGridEventConverter : JsonConverter<EventGridEvent>
{
/// <summary>
/// Gets or sets the serializer to use for the data portion of the <see cref="EventGridEvent"/>. If not specified,
/// JsonObjectSerializer is used.
/// </summary>
/// <inheritdoc cref="JsonConverter{EventGridEvent}.Read(ref Utf8JsonReader, Type, JsonSerializerOptions)"/>
public override EventGridEvent Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
JsonDocument requestDocument = JsonDocument.ParseValue(ref reader);
return new EventGridEvent(EventGridEventInternal.DeserializeEventGridEventInternal(requestDocument.RootElement));
}

/// <inheritdoc cref="JsonConverter{EventGridEvent}.Write(Utf8JsonWriter, EventGridEvent, JsonSerializerOptions)"/>
public override void Write(Utf8JsonWriter writer, EventGridEvent value, JsonSerializerOptions options)
{
JsonDocument data = JsonDocument.Parse(value.Data.ToStream());
var eventGridEventInternal = new EventGridEventInternal(
value.Id,
value.Subject,
data.RootElement,
value.EventType,
value.EventTime,
value.DataVersion)
{
Topic = value.Topic
};
((IUtf8JsonSerializable) eventGridEventInternal).Write(writer);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using System.Threading.Tasks;
using Azure.Core;
using Azure.Core.Pipeline;
using Azure.Messaging.EventGrid.Models;

namespace Azure.Messaging.EventGrid
{
Expand Down Expand Up @@ -160,26 +159,9 @@ private async Task<Response> SendEventsInternal(IEnumerable<EventGridEvent> even

using HttpMessage message = _pipeline.CreateMessage();
Request request = CreateEventRequest(message, "application/json");
var content = new Utf8JsonRequestContent();
content.JsonWriter.WriteStartArray();
foreach (EventGridEvent egEvent in events)
{
JsonDocument data = JsonDocument.Parse(egEvent.Data.ToStream());
EventGridEventInternal newEGEvent = new EventGridEventInternal(
egEvent.Id,
egEvent.Subject,
data.RootElement,
egEvent.EventType,
egEvent.EventTime,
egEvent.DataVersion)
{
Topic = egEvent.Topic
};
content.JsonWriter.WriteObjectValue(newEGEvent);
}

content.JsonWriter.WriteEndArray();
request.Content = content;
// leverage custom converter for EventGridEvent
request.Content = RequestContent.Create(JsonSerializer.Serialize(events));

if (async)
{
Expand Down
32 changes: 32 additions & 0 deletions sdk/eventgrid/Azure.Messaging.EventGrid/tests/ConsumeEventTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,21 @@ public void ParsesEventGridEnvelope()
Assert.AreEqual("1", egEvent.DataVersion);
}

[Test]
public void ParsesEventGridEnvelopeUsingConverter()
{
string requestContent = "[{ \"id\": \"2d1781af-3a4c-4d7c-bd0c-e34b19da4e66\", \"topic\": \"/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\", \"subject\": \"mySubject\", \"data\": { \"validationCode\": \"512d38b6-c7b8-40c8-89fe-f46f9e9622b6\", \"validationUrl\": \"https://rp-eastus2.eventgrid.azure.net:553/eventsubscriptions/estest/validate?id=B2E34264-7D71-453A-B5FB-B62D0FDC85EE&t=2018-04-26T20:30:54.4538837Z&apiVersion=2018-05-01-preview&token=1BNqCxBBSSE9OnNSfZM4%2b5H9zDegKMY6uJ%2fO2DFRkwQ%3d\" }, \"eventType\": \"Microsoft.EventGrid.SubscriptionValidationEvent\", \"eventTime\": \"2018-01-25T22:12:19.4556811Z\", \"metadataVersion\": \"1\", \"dataVersion\": \"1\"}]";

EventGridEvent[] events = JsonSerializer.Deserialize<EventGridEvent[]>(requestContent);
var egEvent = events[0];
Assert.AreEqual("/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", egEvent.Topic);
Assert.AreEqual("2d1781af-3a4c-4d7c-bd0c-e34b19da4e66", egEvent.Id);
Assert.AreEqual("mySubject", egEvent.Subject);
Assert.AreEqual(SystemEventNames.EventGridSubscriptionValidation, egEvent.EventType);
Assert.AreEqual(DateTimeOffset.Parse("2018-01-25T22:12:19.4556811Z"), egEvent.EventTime);
Assert.AreEqual("1", egEvent.DataVersion);
}

[Test]
public void ConsumeStorageBlobDeletedEventWithExtraProperty()
{
Expand Down Expand Up @@ -72,6 +87,23 @@ public void ConsumeEventNotWrappedInAnArray()
}
}

[Test]
public void ConsumeEventNotWrappedInAnArrayWithConverter()
{
string requestContent = "{ \"topic\": \"/subscriptions/id/resourceGroups/Storage/providers/Microsoft.Storage/storageAccounts/xstoretestaccount\", \"subject\": \"/blobServices/default/containers/testcontainer/blobs/testfile.txt\", \"eventType\": \"Microsoft.Storage.BlobDeleted\", \"eventTime\": \"2017-11-07T20:09:22.5674003Z\", \"id\": \"4c2359fe-001e-00ba-0e04-58586806d298\", \"data\": { \"api\": \"DeleteBlob\", \"requestId\": \"4c2359fe-001e-00ba-0e04-585868000000\", \"contentType\": \"text/plain\", \"blobType\": \"BlockBlob\", \"url\": \"https://example.blob.core.windows.net/testcontainer/testfile.txt\", \"sequencer\": \"0000000000000281000000000002F5CA\", \"brandNewProperty\": \"0000000000000281000000000002F5CA\", \"storageDiagnostics\": { \"batchId\": \"b68529f3-68cd-4744-baa4-3c0498ec19f0\" } }, \"dataVersion\": \"\", \"metadataVersion\": \"1\"}";

EventGridEvent egEvent = JsonSerializer.Deserialize<EventGridEvent>(requestContent);

Assert.NotNull(egEvent);
switch (egEvent.EventType)
{
case SystemEventNames.StorageBlobDeleted:
StorageBlobDeletedEventData blobDeleted = egEvent.Data.ToObjectFromJson<StorageBlobDeletedEventData>();
Assert.AreEqual("https://example.blob.core.windows.net/testcontainer/testfile.txt", blobDeleted.Url);
break;
}
}

[Test]
public void ConsumeMultipleEventsInSameBatch()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public async Task RespectsPortFromUriSendingEventGridEvents()

private static List<EventGridEvent> DeserializeRequest(Request request)
{
var content = request.Content as Utf8JsonRequestContent;
var content = request.Content;
var stream = new MemoryStream();
content.WriteTo(stream, CancellationToken.None);
stream.Position = 0;
Expand Down

0 comments on commit f15ec78

Please sign in to comment.