Azure.Messaging.EventGrid (.NET)
Client library for publishing events to Azure Event Grid topics, domains, and namespaces.
Installation
bash
# For topics and domains (push delivery)dotnet add package Azure.Messaging.EventGrid
# For namespaces (pull delivery)dotnet add package Azure.Messaging.EventGrid.Namespaces
# For CloudNative CloudEvents interopdotnet add package Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEventsCurrent Version: 4.28.0 (stable)
Environment Variables
bash
EVENT_GRID_TOPIC_ENDPOINT=https://<topic-name>.<region>.eventgrid.azure.net/api/events # Required: Event Grid topic or domain endpointEVENT_GRID_TOPIC_KEY=<access-key> # Only required for AzureKeyCredential authEVENT_GRID_NAMESPACE_ENDPOINT=https://<namespace>.<region>.eventgrid.azure.net # Optional: Event Grid namespace endpointEVENT_GRID_TOPIC_NAME=<topic-name> # Required: Event Grid topic nameEVENT_GRID_SUBSCRIPTION_NAME=<subscription-name> # Optional: Event Grid subscription nameAZURE_TOKEN_CREDENTIALS=prod # Required only if DefaultAzureCredential is used in productionClient Hierarchy
Push Delivery (Topics/Domains)└── EventGridPublisherClient ├── SendEventAsync(EventGridEvent) ├── SendEventsAsync(IEnumerable<EventGridEvent>) ├── SendEventAsync(CloudEvent) └── SendEventsAsync(IEnumerable<CloudEvent>)
Pull Delivery (Namespaces)├── EventGridSenderClient│ └── SendAsync(CloudEvent)└── EventGridReceiverClient ├── ReceiveAsync() ├── AcknowledgeAsync() ├── ReleaseAsync() └── RejectAsync()Authentication
API Key Authentication
csharp
using Azure;using Azure.Messaging.EventGrid;
EventGridPublisherClient client = new( new Uri("https://mytopic.eastus-1.eventgrid.azure.net/api/events"), new AzureKeyCredential("<access-key>"));Microsoft Entra Token Credential
csharp
using Azure.Identity;using Azure.Messaging.EventGrid;
// Local dev: DefaultAzureCredential. Production: set AZURE_TOKEN_CREDENTIALS=prod or AZURE_TOKEN_CREDENTIALS=<specific_credential>var credential = new DefaultAzureCredential( DefaultAzureCredential.DefaultEnvironmentVariableName);// Or use a specific credential directly in production:// See https://learn.microsoft.com/dotnet/api/overview/azure/identity-readme?view=azure-dotnet#credential-classes// var credential = new ManagedIdentityCredential();EventGridPublisherClient client = new( new Uri("https://mytopic.eastus-1.eventgrid.azure.net/api/events"), credential);SAS Token Authentication
csharp
string sasToken = EventGridPublisherClient.BuildSharedAccessSignature( new Uri(topicEndpoint), DateTimeOffset.UtcNow.AddHours(1), new AzureKeyCredential(topicKey));
var sasCredential = new AzureSasCredential(sasToken);EventGridPublisherClient client = new( new Uri(topicEndpoint), sasCredential);Publishing Events
EventGridEvent Schema
csharp
EventGridPublisherClient client = new( new Uri(topicEndpoint), new AzureKeyCredential(topicKey));
// Single eventEventGridEvent egEvent = new( subject: "orders/12345", eventType: "Order.Created", dataVersion: "1.0", data: new { OrderId = "12345", Amount = 99.99 });
await client.SendEventAsync(egEvent);
// Batch of eventsList<EventGridEvent> events = new(){ new EventGridEvent( subject: "orders/12345", eventType: "Order.Created", dataVersion: "1.0", data: new OrderData { OrderId = "12345", Amount = 99.99 }), new EventGridEvent( subject: "orders/12346", eventType: "Order.Created", dataVersion: "1.0", data: new OrderData { OrderId = "12346", Amount = 149.99 })};
await client.SendEventsAsync(events);CloudEvent Schema
csharp
CloudEvent cloudEvent = new( source: "/orders/system", type: "Order.Created", data: new { OrderId = "12345", Amount = 99.99 });
cloudEvent.Subject = "orders/12345";cloudEvent.Id = Guid.NewGuid().ToString();cloudEvent.Time = DateTimeOffset.UtcNow;
await client.SendEventAsync(cloudEvent);
// Batch of CloudEventsList<CloudEvent> cloudEvents = new(){ new CloudEvent("/orders", "Order.Created", new { OrderId = "1" }), new CloudEvent("/orders", "Order.Updated", new { OrderId = "2" })};
await client.SendEventsAsync(cloudEvents);Publishing to Event Grid Domain
csharp
// Events must specify the Topic property for domain routingList<EventGridEvent> events = new(){ new EventGridEvent( subject: "orders/12345", eventType: "Order.Created", dataVersion: "1.0", data: new { OrderId = "12345" }) { Topic = "orders-topic" // Domain topic name }, new EventGridEvent( subject: "inventory/item-1", eventType: "Inventory.Updated", dataVersion: "1.0", data: new { ItemId = "item-1" }) { Topic = "inventory-topic" }};
await client.SendEventsAsync(events);Custom Serialization
csharp
using System.Text.Json;
var serializerOptions = new JsonSerializerOptions{ PropertyNamingPolicy = JsonNamingPolicy.CamelCase};
var customSerializer = new JsonObjectSerializer(serializerOptions);
EventGridEvent egEvent = new( subject: "orders/12345", eventType: "Order.Created", dataVersion: "1.0", data: customSerializer.Serialize(new OrderData { OrderId = "12345" }));
await client.SendEventAsync(egEvent);Pull Delivery (Namespaces)
Send Events to Namespace Topic
csharp
using Azure;using Azure.Messaging;using Azure.Messaging.EventGrid.Namespaces;
var senderClient = new EventGridSenderClient( new Uri(namespaceEndpoint), topicName, new AzureKeyCredential(topicKey));
// Send single eventCloudEvent cloudEvent = new("employee_source", "Employee.Created", new { Name = "John", Age = 30 });await senderClient.SendAsync(cloudEvent);
// Send batchawait senderClient.SendAsync(new[]{ new CloudEvent("source", "type", new { Name = "Alice" }), new CloudEvent("source", "type", new { Name = "Bob" })});Receive and Process Events
csharp
var receiverClient = new EventGridReceiverClient( new Uri(namespaceEndpoint), topicName, subscriptionName, new AzureKeyCredential(topicKey));
// Receive eventsReceiveResult result = await receiverClient.ReceiveAsync(maxEvents: 10);
List<string> lockTokensToAck = new();List<string> lockTokensToRelease = new();
foreach (ReceiveDetails detail in result.Details){ CloudEvent cloudEvent = detail.Event; string lockToken = detail.BrokerProperties.LockToken; try { // Process the event Console.WriteLine($"Event: {cloudEvent.Type}, Data: {cloudEvent.Data}"); lockTokensToAck.Add(lockToken); } catch (Exception) { // Release for retry lockTokensToRelease.Add(lockToken); }}
// Acknowledge successfully processed eventsif (lockTokensToAck.Any()){ await receiverClient.AcknowledgeAsync(lockTokensToAck);}
// Release events for retryif (lockTokensToRelease.Any()){ await receiverClient.ReleaseAsync(lockTokensToRelease);}Reject Events (Dead Letter)
csharp
// Reject events that cannot be processedawait receiverClient.RejectAsync(new[] { lockToken });Consuming Events (Azure Functions)
EventGridEvent Trigger
csharp
using Azure.Messaging.EventGrid;using Microsoft.Azure.WebJobs;using Microsoft.Azure.WebJobs.Extensions.EventGrid;
public static class EventGridFunction{ [FunctionName("ProcessEventGridEvent")] public static void Run( [EventGridTrigger] EventGridEvent eventGridEvent, ILogger log) { log.LogInformation($"Event Type: {eventGridEvent.EventType}"); log.LogInformation($"Subject: {eventGridEvent.Subject}"); log.LogInformation($"Data: {eventGridEvent.Data}"); }}CloudEvent Trigger
csharp
using Azure.Messaging;using Microsoft.Azure.Functions.Worker;
public class CloudEventFunction{ [Function("ProcessCloudEvent")] public void Run( [EventGridTrigger] CloudEvent cloudEvent, FunctionContext context) { var logger = context.GetLogger("ProcessCloudEvent"); logger.LogInformation($"Event Type: {cloudEvent.Type}"); logger.LogInformation($"Source: {cloudEvent.Source}"); logger.LogInformation($"Data: {cloudEvent.Data}"); }}Parsing Events
Parse EventGridEvent
csharp
// From JSON stringstring json = "..."; // Event Grid webhook payloadEventGridEvent[] events = EventGridEvent.ParseMany(BinaryData.FromString(json));
foreach (EventGridEvent egEvent in events){ if (egEvent.TryGetSystemEventData(out object systemEvent)) { // Handle system event switch (systemEvent) { case StorageBlobCreatedEventData blobCreated: Console.WriteLine($"Blob created: {blobCreated.Url}"); break; } } else { // Handle custom event var customData = egEvent.Data.ToObjectFromJson<MyCustomData>(); }}Parse CloudEvent
csharp
CloudEvent[] cloudEvents = CloudEvent.ParseMany(BinaryData.FromString(json));
foreach (CloudEvent cloudEvent in cloudEvents){ var data = cloudEvent.Data.ToObjectFromJson<MyEventData>(); Console.WriteLine($"Type: {cloudEvent.Type}, Data: {data}");}System Events
csharp
// Common system event typesusing Azure.Messaging.EventGrid.SystemEvents;
// Storage eventsStorageBlobCreatedEventData blobCreated;StorageBlobDeletedEventData blobDeleted;
// Resource eventsResourceWriteSuccessEventData resourceCreated;ResourceDeleteSuccessEventData resourceDeleted;
// App Service eventsWebAppUpdatedEventData webAppUpdated;
// Container Registry eventsContainerRegistryImagePushedEventData imagePushed;
// IoT Hub eventsIotHubDeviceCreatedEventData deviceCreated;Key Types Reference
| Type | Purpose |
|---|---|
EventGridPublisherClient | Publish to topics/domains |
EventGridSenderClient | Send to namespace topics |
EventGridReceiverClient | Receive from namespace subscriptions |
EventGridEvent | Event Grid native schema |
CloudEvent | CloudEvents 1.0 schema |
ReceiveResult | Pull delivery response |
ReceiveDetails | Event with broker properties |
BrokerProperties | Lock token, delivery count |
Event Schemas Comparison
| Feature | EventGridEvent | CloudEvent |
|---|---|---|
| Standard | Azure-specific | CNCF standard |
| Required fields | subject, eventType, dataVersion, data | source, type |
| Extensibility | Limited | Extension attributes |
| Interoperability | Azure only | Cross-platform |
Best Practices
- Use CloudEvents — Prefer CloudEvents for new implementations (industry standard)
- Batch events — Send multiple events in one call for efficiency
- Use Entra ID — Prefer managed identity over access keys
- Idempotent handlers — Events may be delivered more than once
- Set event TTL — Configure time-to-live for namespace events
- Handle partial failures — Acknowledge/release events individually
- Use dead-letter — Configure dead-letter for failed events
- Validate schemas — Validate event data before processing
Error Handling
csharp
using Azure;
try{ await client.SendEventAsync(cloudEvent);}catch (RequestFailedException ex) when (ex.Status == 401){ Console.WriteLine("Authentication failed - check credentials");}catch (RequestFailedException ex) when (ex.Status == 403){ Console.WriteLine("Authorization failed - check RBAC permissions");}catch (RequestFailedException ex) when (ex.Status == 413){ Console.WriteLine("Payload too large - max 1MB per event, 1MB total batch");}catch (RequestFailedException ex){ Console.WriteLine($"Event Grid error: {ex.Status} - {ex.Message}");}Failover Pattern
csharp
try{ var primaryClient = new EventGridPublisherClient(primaryUri, primaryKey); await primaryClient.SendEventsAsync(events);}catch (RequestFailedException){ // Failover to secondary region var secondaryClient = new EventGridPublisherClient(secondaryUri, secondaryKey); await secondaryClient.SendEventsAsync(events);}Related SDKs
| SDK | Purpose | Install |
|---|---|---|
Azure.Messaging.EventGrid | Topics/Domains (this SDK) | dotnet add package Azure.Messaging.EventGrid |
Azure.Messaging.EventGrid.Namespaces | Pull delivery | dotnet add package Azure.Messaging.EventGrid.Namespaces |
Azure.Identity | Authentication | dotnet add package Azure.Identity |
Microsoft.Azure.WebJobs.Extensions.EventGrid | Azure Functions trigger | dotnet add package Microsoft.Azure.WebJobs.Extensions.EventGrid |



