| name | azure-eventgrid-dotnet |
| description | ALWAYS use this when the user mentions Azure Eventgrid Dotnet, asks to build, debug, review, document, automate, test, configure, migrate, or make decisions in this domain, or the task clearly depends on Azure Eventgrid Dotnet; scope: Azure Event Grid SDK for .NET. Apply the bundled workflow, references, scripts, Senior Master standard, and Codex strict review gate before final output. |
Azure.Messaging.EventGrid (.NET)
Selective Reading Rule
Start with:
references/senior-master-standard.md
references/usage-routing.md
references/quality-checklist.md
Then load only the inherited docs, scripts, assets, or examples that match the user's actual task.
Client library for publishing events to Azure Event Grid topics, domains, and namespaces.
Installation
dotnet add package Azure.Messaging.EventGrid
dotnet add package Azure.Messaging.EventGrid.Namespaces
dotnet add package Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents
Current Version: 4.28.0 (stable)
Environment Variables
EVENT_GRID_TOPIC_ENDPOINT=https://<topic-name>.<region>.eventgrid.azure.net/api/events
EVENT_GRID_TOPIC_KEY=<access-key>
EVENT_GRID_NAMESPACE_ENDPOINT=https://<namespace>.<region>.eventgrid.azure.net
EVENT_GRID_TOPIC_NAME=<topic-name>
EVENT_GRID_SUBSCRIPTION_NAME=<subscription-name>
Client 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
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 ID (Recommended)
using Azure.Identity;
using Azure.Messaging.EventGrid;
EventGridPublisherClient client = new(
new Uri("https://mytopic.eastus-1.eventgrid.azure.net/api/events"),
new DefaultAzureCredential());
SAS Token Authentication
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
EventGridPublisherClient client = new(
new Uri(topicEndpoint),
new AzureKeyCredential(topicKey));
EventGridEvent egEvent = new(
subject: "orders/12345",
eventType: "Order.Created",
dataVersion: "1.0",
data: new { OrderId = "12345", Amount = 99.99 });
await client.SendEventAsync(egEvent);
List<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
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);
List<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
List<EventGridEvent> events = new()
{
new EventGridEvent(
subject: "orders/12345",
eventType: "Order.Created",
dataVersion: "1.0",
data: new { OrderId = "12345" })
{
Topic = "orders-topic"
},
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
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
using Azure;
using Azure.Messaging;
using Azure.Messaging.EventGrid.Namespaces;
var senderClient = new EventGridSenderClient(
new Uri(namespaceEndpoint),
topicName,
new AzureKeyCredential(topicKey));
CloudEvent cloudEvent = new("employee_source", "Employee.Created",
new { Name = "John", Age = 30 });
await senderClient.SendAsync(cloudEvent);
await senderClient.SendAsync(new[]
{
new CloudEvent("source", "type", new { Name = "Alice" }),
new CloudEvent("source", "type", new { Name = "Bob" })
});
Receive and Process Events
var receiverClient = new EventGridReceiverClient(
new Uri(namespaceEndpoint),
topicName,
subscriptionName,
new AzureKeyCredential(topicKey));
ReceiveResult 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
{
Console.WriteLine($"Event: {cloudEvent.Type}, Data: {cloudEvent.Data}");
lockTokensToAck.Add(lockToken);
}
catch (Exception)
{
lockTokensToRelease.Add(lockToken);
}
}
if (lockTokensToAck.Any())
{
await receiverClient.AcknowledgeAsync(lockTokensToAck);
}
if (lockTokensToRelease.Any())
{
await receiverClient.ReleaseAsync(lockTokensToRelease);
}
Reject Events (Dead Letter)
await receiverClient.RejectAsync(new[] { lockToken });
Consuming Events (Azure Functions)
EventGridEvent Trigger
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
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
string json = "...";
EventGridEvent[] events = EventGridEvent.ParseMany(BinaryData.FromString(json));
foreach (EventGridEvent egEvent in events)
{
if (egEvent.TryGetSystemEventData(out object systemEvent))
{
switch (systemEvent)
{
case StorageBlobCreatedEventData blobCreated:
Console.WriteLine($"Blob created: {blobCreated.Url}");
break;
}
}
else
{
var customData = egEvent.Data.ToObjectFromJson<MyCustomData>();
}
}
Parse CloudEvent
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
using Azure.Messaging.EventGrid.SystemEvents;
StorageBlobCreatedEventData blobCreated;
StorageBlobDeletedEventData blobDeleted;
ResourceWriteSuccessEventData resourceCreated;
ResourceDeleteSuccessEventData resourceDeleted;
WebAppUpdatedEventData webAppUpdated;
ContainerRegistryImagePushedEventData imagePushed;
IotHubDeviceCreatedEventData 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
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
try
{
var primaryClient = new EventGridPublisherClient(primaryUri, primaryKey);
await primaryClient.SendEventsAsync(events);
}
catch (RequestFailedException)
{
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 |
Reference Links
When to Use
This skill is applicable to execute the workflow or actions described in the overview.
Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.