This guide is intended to assist in the migration to Azure.Messaging.EventGrid
from Microsoft.Azure.EventGrid
. It will focus on side-by-side comparisons for similar operations between the two packages.
We assume that you are familiar with Microsoft.Azure.EventGrid
. If not, please refer to the README for Azure.Messaging.EventGrid
rather than this guide.
As Azure has matured and been embraced by a more diverse group of developers, we have been focused on learning the patterns and practices to best support developer productivity and to understand the gaps that the .NET client libraries have.
There were several areas of consistent feedback expressed across the Azure client library ecosystem. One of the most important is that the client libraries for different Azure services have not had a consistent approach to organization, naming, and API structure. Additionally, many developers have felt that the learning curve was difficult, and the APIs did not offer a good, approachable, and consistent onboarding story for those learning Azure or exploring a specific Azure service.
To improve the development experience across Azure services, a set of uniform design guidelines was created for all languages to drive a consistent experience with established API patterns for all services. A set of .NET design guidelines was also introduced to ensure that .NET clients have a natural and idiomatic feel with respect to the .NET ecosystem. The new Azure.Messaging.EventGrid library follows these guidelines.
The modern Azure.Messaging.EventGrid
client library also provides the ability to share in some of the cross-service improvements made to the Azure development experience, such as:
- Using the new Azure.Identity library to share a single authentication approach between clients
- A unified logging and diagnostics pipeline offering a common view of the activities across each of the client libraries
The new Azure.Messaging.EventGrid library includes several new features:
- Publishing and deserializing CloudEvents using the Azure.Core
CloudEvent
type - Methods that allow publishing a single event in addition to lists of events
- Ability to use a custom serializer for the Data of an event
- Ability to publish events with a custom schema
- Generate a shared access signature token using the
EventGridSasBuilder
Package names and the namespace root for the modern Azure client libraries for .NET have changed. Each will follow the pattern Azure.[Area].[Service]
where the legacy clients followed the pattern Microsoft.Azure.[Service]
. This provides a quick and accessible means to help understand, at a glance, whether you are using the modern or legacy clients.
In the case of Event Grid, the modern client libraries have packages and namespaces that begin with Azure.Messaging.EventGrid and were released beginning with version 4. The legacy client libraries have packages and namespaces that begin with Microsoft.Azure.EventGrid and a version of 3.x.x or below.
In Microsoft.Azure.EventGrid
, the EventGridClient
was instantiated by passing the TopicCredentials
into the constructor:
string topicEndpoint = "https://<topic-name>.<region>-1.eventgrid.azure.net/api/events";
string topicKey = "<topic-key>";
TopicCredentials topicCredentials = new TopicCredentials(topicKey);
EventGridClient client = new EventGridClient(topicCredentials);
In the Azure.Messaging.EventGrid
library, the client used to interact with the service was renamed as the EventGridPublisherClient
to highlight the fact that the client is only used to publish events and does not consume events from the service. The constructor takes the topic endpoint in addition to a credential parameter since a single client will only ever be able to publish to a single topic.
EventGridPublisherClient client = new EventGridPublisherClient(
new Uri(topicEndpoint),
new AzureKeyCredential(topicAccessKey));
In the Microsoft.Azure.EventGrid
library, events were published as shown:
string topicEndpoint = "https://<topic-name>.<region>-1.eventgrid.azure.net/api/events";
string topicHostname = new Uri(topicEndpoint).Host;
List<EventGridEvent> eventsList = new List<EventGridEvent>();
for (int i = 0; i < 1; i++)
{
eventsList.Add(new EventGridEvent()
{
Id = Guid.NewGuid().ToString(),
EventType = "Contoso.Items.ItemReceivedEvent",
Data = new ContosoItemReceivedEventData()
{
ItemUri = "ContosoSuperItemUri"
},
EventTime = DateTime.Now,
Subject = "Door1",
DataVersion = "2.0"
});
}
await client.PublishEventsAsync(topicHostname, eventsList);
In Azure.Messaging.EventGrid
, when publishing events it is no longer necessary to include the topic host name. Instead, this is passed as part of the Uri
that is provided to the EventGridPublisherClient
constructor. The EventGridEvent
type now has a constructor that includes parameters for all required fields of the event grid schema:
// Example of a custom ObjectSerializer used to serialize the event payload to JSON
var myCustomDataSerializer = new JsonObjectSerializer(
new JsonSerializerOptions()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
// Add EventGridEvents to a list to publish to the topic
List<EventGridEvent> eventsList = new List<EventGridEvent>
{
// EventGridEvent with custom model serialized to JSON
new EventGridEvent(
"ExampleEventSubject",
"Example.EventType",
"1.0",
new CustomModel() { A = 5, B = true }),
// EventGridEvent with custom model serialized to JSON using a custom serializer
new EventGridEvent(
"ExampleEventSubject",
"Example.EventType",
"1.0",
myCustomDataSerializer.Serialize(new CustomModel() { A = 5, B = true })),
};
// Send the events
await client.SendEventsAsync(eventsList);
In Microsoft.Azure.EventGrid
, there was the EventGridSubscriber
type that was used to deserialize events:
string requestContent = await req.Content.ReadAsStringAsync();
EventGridSubscriber eventGridSubscriber = new EventGridSubscriber();
// Optionally add one or more custom event type mappings
eventGridSubscriber.AddOrUpdateCustomEventMapping("Contoso.Items.ItemReceived", typeof(ContosoItemReceivedEventData));
EventGridEvent[] events = eventGridSubscriber.DeserializeEventGridEvents(requestContent);
foreach (EventGridEvent receivedEvent in events)
{
if (receivedEvent.Data is SubscriptionValidationEventData)
{
SubscriptionValidationEventData eventData = (SubscriptionValidationEventData)receivedEvent.Data;
log.Info($"Got SubscriptionValidation event data, validationCode: {eventData.ValidationCode}, validationUrl: {eventData.ValidationUrl}, topic: {eventGridEvent.Topic}");
// Handle subscription validation
}
else if (receivedEvent.Data is StorageBlobCreatedEventData)
{
StorageBlobCreatedEventData eventData = (StorageBlobCreatedEventData)receivedEvent.Data;
log.Info($"Got BlobCreated event data, blob URI {eventData.Url}");
// Handle StorageBlobCreatedEventData
}
else if (receivedEvent.Data is ContosoItemReceivedEventData)
{
ContosoItemReceivedEventData eventData = (ContosoItemReceivedEventData)receivedEvent.Data;
}
}
In the Azure.Messaging.EventGrid
library, there is no longer a separate type to deserialize events. Instead, you can use static factory methods on EventGridEvent
to parse into an array of EventGridEvents
.
// Parse the JSON payload into a list of events
EventGridEvent[] egEvents = EventGridEvent.ParseMany(BinaryData.FromStream(httpContent));
You can then iterate through your events and deserialize the data.
foreach (EventGridEvent egEvent in egEvents)
{
// If the event is a system event, TryGetSystemEventData will return the deserialized system event
if (egEvent.TryGetSystemEventData(out object systemEvent))
{
switch (systemEvent)
{
case SubscriptionValidationEventData subscriptionValidated:
Console.WriteLine(subscriptionValidated.ValidationCode);
break;
case StorageBlobCreatedEventData blobCreated:
Console.WriteLine(blobCreated.BlobType);
break;
// Handle any other system event type
default:
Console.WriteLine(egEvent.EventType);
// we can get the raw Json for the event using Data
Console.WriteLine(egEvent.Data.ToString());
break;
}
}
else
{
switch (egEvent.EventType)
{
case "MyApp.Models.CustomEventType":
TestPayload deserializedEventData = egEvent.Data.ToObjectFromJson<TestPayload>();
Console.WriteLine(deserializedEventData.Name);
break;
// Handle any other custom event type
default:
Console.Write(egEvent.EventType);
Console.WriteLine(egEvent.Data.ToString());
break;
}
}
}
More examples can be found at: