Azure / azure-sdk-for-net

This repository is for active development of the Azure SDK for .NET. For consumers of the SDK we recommend visiting our public developer docs at https://learn.microsoft.com/dotnet/azure/ or our versioned developer docs at https://azure.github.io/azure-sdk-for-net.
MIT License
5.17k stars 4.53k forks source link

[BUG] Data property not populated for EventGridEvent object #32969

Closed nikneem closed 1 year ago

nikneem commented 1 year ago

Library name and version

Azure.Messaging.EventGrid 4.12.0

Describe the bug

I want to send an event using event grid, with some data. I have the following snippet of C# code:

_logger.LogInformation("Broadcasting event grid message {msg}", JsonConvert.SerializeObject( blackJackEvent));
var cloudEvent = new EventGridEvent(
    blackJackEvent.EventSource, 
    blackJackEvent.EventType, 
    blackJackEvent.Version, 
    BinaryData.FromObjectAsJson(blackJackEvent.Data));
_logger.LogInformation("EventGridEvent with data {event}", JsonConvert.SerializeObject(cloudEvent));
var response = await _client.SendEventAsync(cloudEvent);

The blackJackEvent object contains data (two properties of type Guid). Now when the event is sent to event grid, I successfully receive the message, but the data property is empty.

After investigating the log messages show, that the data disappears when creating the EventGridEvent object. Te log messages look like so:

Broadcasting event grid message {"EventType":"Session.Created","Version":"v1","Data":{"UserId":"6035077c-c86f-48b7-968d-ba5d8ad91958","SessionId":"3c721b52-c255-4b96-9a3a-fdc474e84bb2"},"EventSource":"cloudevents/blackjack/sessions"}

EventGridEvent with data {"Data":{},"Id":"a32560bd-7250-4132-b07e-5066b7e258a1","Topic":null,"Subject":"cloudevents/blackjack/sessions","EventType":"Session.Created","EventTime":"2022-12-08T13:55:40.3525145+00:00","DataVersion":"v1"}

As you can see, the data was there when creating the EventGridEvent object, but is not successfully passed through for some reason.

Expected behavior

I would expect the data to be present in the EventGridEvent object so the receiving side of the event can handle the event properly

Actual behavior

The data property is not populated for some reason and the receiving side receives an empty data object.

Reproduction Steps

Use the code snippet obove

Environment

Just standard .NET 7, hosted on Azure using Azure Container Apps and Docker

jsquire commented 1 year ago

Thank you for your feedback. Tagging and routing to the team member best able to assist.

nikneem commented 1 year ago

A little bit more background may be of help. I'm trying to create a demo project to show how to create a proper microservices solution in Azure using Azure Container Apps. I want to use the Event Grid to broadcast events when 'something' happens in one of the services. I created a separate library for the events so I have all the event names and types in a single place. This library also creates an instance of the EventGridPublisherClient to publish the events. I use the Event Grid Schema for events.

The full source code of the library is open source and MIT licensed: https://github.com/nikneem/blackjack-events

Maybe this background information and full source code help.

JoshLove-msft commented 1 year ago

The snippet you've provided here looks like it should work:

var cloudEvent = new EventGridEvent(
    blackJackEvent.EventSource, 
    blackJackEvent.EventType, 
    blackJackEvent.Version, 
    BinaryData.FromObjectAsJson(blackJackEvent.Data));

However, in the repo you linked, I see this:

      var cloudEvent = new EventGridEvent(
          blackJackEvent.EventSource, 
          blackJackEvent.EventType, 
          blackJackEvent.Version,
          JsonConvert.SerializeObject(blackJackEvent.Data));

When using the constructor that takes an object data you would just pass in the serializable object, i.e.:

      var cloudEvent = new EventGridEvent(
          blackJackEvent.EventSource, 
          blackJackEvent.EventType, 
          blackJackEvent.Version,
          blackJackEvent.Data);

The logs you are emitting won't work because you are attempting to serialize the EventGridEvent with NewtonSoft. Instead you can use System.Text.Json to serialize the event.

One other point to note as an FYI - you call the event variable cloudEvent but it is actually an EventGridEvent. The Event Grid client library also supports publishing CloudEvent.

nikneem commented 1 year ago

Hi Josh, Thanks for your attention. The fact the code snippet in this issue is different from the code in the GH repo is that I'm working on it and trying to get the problem fixed. I found that serialization of the Data property fails for some reason and therefore does not end up in the EventGridEvent.

I realize the naming problem between EventGridEvent end CloudEvent is there, I do use the EventGridEvent so the cloudEvent naming will be removed.

For now, I think the problem is on my side, being the serialization issue. I will get back on it once I got that sorted out.

nikneem commented 1 year ago

Yeah, this is confirmed. I had a local issue serializing data and it, therefore, did not end up in the EventGridEvent object. The code in the original post:

var cloudEvent = new EventGridEvent(
    blackJackEvent.EventSource, 
    blackJackEvent.EventType, 
    blackJackEvent.Version, 
    BinaryData.FromObjectAsJson(blackJackEvent.Data));

is now changed to a function that will convert the local project event into a EventGridEvent object and this function works fine and as expected:

    private EventGridEvent ToEventGridEvent<TEventData>(IBlackJackEvent<TEventData> blackJackEvent)
    {
        var jsonData = JsonSerializer.Serialize(blackJackEvent.Data);
        return new EventGridEvent(
            blackJackEvent.EventSource,
            blackJackEvent.EventType,
            blackJackEvent.Version,
            jsonData);
    }

However... knowing the cause of my specific problem, I would have expected an exception to occur. This issue might be left open for implementing an exception in case data serialization fails.

The initial code I created for publishing the event looks like so:

var cloudEvent = new EventGridEvent(
    blackJackEvent.EventSource, 
    blackJackEvent.EventType, 
    blackJackEvent.Version, 
    blackJackEvent.Data);

Passing in the plain Data property of the blackJackEvent should make the constructor of the EventGridEvent serialize the data, which apparently failed. This is where I would expect that exception.

JoshLove-msft commented 1 year ago

I'm not sure why the last snippet wouldn't work. Your Data property is a public class with two public properties. This constructor would create a new instance of BinaryData, which would ultimately call JsonSerializer.SerializeToUtf8Bytes. If JsonSerializer.Serialize works, I don't see why SerializeToUtf8Bytes would fail.

Can you inspect the Data property after constructing the EventGridEvent when passing in the plain object?

ghost commented 1 year ago

Hi, we're sending this friendly reminder because we haven't heard back from you in 7 days. We need more information about this issue to help address it. Please be sure to give us your input. If we don't hear back from you within 14 days of this comment the issue will be automatically closed. Thank you!