Back to Blog
3 min read

Azure Event Grid Custom Topics: Event-Driven Architecture

Azure Event Grid enables event-driven architectures with reliable event delivery. Custom topics let you publish your own events to Event Grid.

Event Grid Concepts

  • Topic: Endpoint where events are sent
  • Event Subscription: Routes events to handlers
  • Event Handler: Service that receives events
  • Event Schema: Structure of event data

Create Custom Topic

# Create Event Grid topic
az eventgrid topic create \
    --name my-custom-topic \
    --resource-group myRG \
    --location eastus

# Get topic endpoint and key
az eventgrid topic show \
    --name my-custom-topic \
    --resource-group myRG \
    --query endpoint

az eventgrid topic key list \
    --name my-custom-topic \
    --resource-group myRG \
    --query key1

Event Schema

[
    {
        "id": "unique-event-id",
        "eventType": "Order.Created",
        "subject": "/orders/12345",
        "eventTime": "2021-01-11T10:30:00Z",
        "data": {
            "orderId": "12345",
            "customerId": "cust-789",
            "amount": 299.99,
            "items": [
                { "productId": "prod-1", "quantity": 2 }
            ]
        },
        "dataVersion": "1.0"
    }
]

Publish Events (.NET)

using Azure;
using Azure.Messaging.EventGrid;

var endpoint = new Uri("https://my-custom-topic.eastus-1.eventgrid.azure.net/api/events");
var credential = new AzureKeyCredential("your-key");
var client = new EventGridPublisherClient(endpoint, credential);

// Create event
var orderEvent = new EventGridEvent(
    subject: "/orders/12345",
    eventType: "Order.Created",
    dataVersion: "1.0",
    data: new
    {
        OrderId = "12345",
        CustomerId = "cust-789",
        Amount = 299.99m,
        CreatedAt = DateTime.UtcNow
    }
);

// Publish event
await client.SendEventAsync(orderEvent);
Console.WriteLine("Event published");

// Publish batch
var events = new List<EventGridEvent>
{
    new EventGridEvent("/orders/123", "Order.Created", "1.0", orderData1),
    new EventGridEvent("/orders/124", "Order.Created", "1.0", orderData2),
    new EventGridEvent("/orders/125", "Order.Shipped", "1.0", orderData3)
};

await client.SendEventsAsync(events);

Create Event Subscription

# Subscribe Azure Function to topic
az eventgrid event-subscription create \
    --name order-processor-subscription \
    --source-resource-id /subscriptions/.../topics/my-custom-topic \
    --endpoint-type azurefunction \
    --endpoint /subscriptions/.../functions/ProcessOrder

# Subscribe webhook
az eventgrid event-subscription create \
    --name webhook-subscription \
    --source-resource-id /subscriptions/.../topics/my-custom-topic \
    --endpoint https://myapi.com/webhooks/eventgrid

# Subscribe with filters
az eventgrid event-subscription create \
    --name filtered-subscription \
    --source-resource-id /subscriptions/.../topics/my-custom-topic \
    --endpoint https://myapi.com/webhooks/orders \
    --event-types Order.Created Order.Updated \
    --subject-begins-with /orders/ \
    --subject-ends-with /priority

Handle Events (Azure Function)

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.EventGrid;
using Azure.Messaging.EventGrid;

public static class OrderProcessor
{
    [FunctionName("ProcessOrder")]
    public static async Task Run(
        [EventGridTrigger] EventGridEvent eventGridEvent,
        ILogger log)
    {
        log.LogInformation($"Event type: {eventGridEvent.EventType}");
        log.LogInformation($"Subject: {eventGridEvent.Subject}");
        log.LogInformation($"Data: {eventGridEvent.Data}");

        // Deserialize event data
        var orderData = eventGridEvent.Data.ToObjectFromJson<OrderCreatedData>();

        // Process the order
        await ProcessOrderAsync(orderData);
    }
}

public record OrderCreatedData(
    string OrderId,
    string CustomerId,
    decimal Amount,
    DateTime CreatedAt
);

Advanced Filtering

# Advanced filter with multiple conditions
az eventgrid event-subscription create \
    --name advanced-filtered \
    --source-resource-id /subscriptions/.../topics/my-custom-topic \
    --endpoint https://myapi.com/webhooks \
    --advanced-filter data.amount NumberGreaterThan 100 \
    --advanced-filter data.priority StringIn high critical

Dead-lettering

# Enable dead-letter destination
az eventgrid event-subscription create \
    --name with-deadletter \
    --source-resource-id /subscriptions/.../topics/my-custom-topic \
    --endpoint https://myapi.com/webhooks \
    --deadletter-endpoint /subscriptions/.../storageAccounts/mystorage/blobServices/default/containers/deadletter

CloudEvents Schema

// Use CloudEvents format
var cloudEvent = new CloudEvent(
    source: "/myapp/orders",
    type: "order.created",
    data: new { OrderId = "12345", Amount = 99.99 }
);

var client = new EventGridPublisherClient(endpoint, credential);
await client.SendEventAsync(cloudEvent);

Event Grid: reliable event delivery at massive scale.

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.