Documentation Index Fetch the complete documentation index at: https://mintlify.com/IntentArchitect/Intent.Modules.NET/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The Azure Functions Event Grid module enables Azure Functions to receive and dispatch Event Grid events to event handlers. This provides a serverless, event-driven architecture for reacting to changes across Azure services and custom applications.
Azure Event Grid is a fully managed event routing service that enables event-driven, reactive programming using a publish-subscribe model.
Installation
Intent.AzureFunctions.AzureEventGrid
Dependencies
Intent.AzureFunctions - Core Azure Functions support
Intent.Eventing.AzureEventGrid - Event Grid eventing contracts
Intent.Eventing.Contracts - Base eventing infrastructure
Event Grid Basics
Key Concepts
Topics - Endpoints where events are published
Event Subscriptions - Routes that filter and deliver events
Event Handlers - Applications that respond to events
Events - JSON messages describing what happened
Event Grid vs Service Bus
Feature Event Grid Service Bus Pattern Event distribution Message queuing Latency Sub-second Seconds Ordering Not guaranteed Guaranteed (sessions) Use Case Event notifications Transaction processing
Modeling Event Grid Consumers
In the Services Designer
Create Integration Events in the Eventing designer
Add Event Grid stereotype to mark events for Event Grid
Model Event Handlers that subscribe to Event Grid events
Generated Consumer
Intent Architect generates Azure Functions that consume Event Grid events:
public class BlobCreatedConsumer
{
private readonly IIntegrationEventHandler < BlobCreatedEvent > _handler ;
public BlobCreatedConsumer ( IIntegrationEventHandler < BlobCreatedEvent > handler )
{
_handler = handler ;
}
[ Function ( "BlobCreatedConsumer" )]
public async Task Run (
[ EventGridTrigger ] EventGridEvent eventGridEvent ,
CancellationToken cancellationToken )
{
var blobEvent = eventGridEvent . Data . ToObjectFromJson < BlobCreatedEvent >();
await _handler . HandleAsync ( blobEvent , cancellationToken );
}
}
Event Grid Event Structure
Event Grid events follow this schema:
{
"id" : "unique-event-id" ,
"eventType" : "Microsoft.Storage.BlobCreated" ,
"subject" : "/blobServices/default/containers/mycontainer/blobs/myfile.txt" ,
"eventTime" : "2024-01-15T10:30:00Z" ,
"data" : {
"api" : "PutBlob" ,
"clientRequestId" : "request-id" ,
"requestId" : "server-request-id" ,
"url" : "https://myaccount.blob.core.windows.net/mycontainer/myfile.txt"
},
"dataVersion" : "1.0" ,
"metadataVersion" : "1" ,
"topic" : "/subscriptions/{subscription-id}/resourceGroups/..."
}
Event Sources
Azure Services
Event Grid supports many Azure service event sources:
Blob Storage Blob created, deleted, archived
Resource Manager Resource created, updated, deleted
IoT Hub Device created, deleted, telemetry
Container Registry Image pushed, deleted
Custom Topics
Publish custom events to Event Grid:
public class OrderService
{
private readonly EventGridPublisherClient _client ;
public async Task CreateOrderAsync ( CreateOrderCommand command )
{
// Create order
var order = await _repository . CreateAsync ( command );
// Publish to Event Grid
var eventGridEvent = new EventGridEvent (
subject : $"orders/ { order . Id } " ,
eventType : "Contoso.Orders.OrderCreated" ,
dataVersion : "1.0" ,
data : new OrderCreatedEvent
{
OrderId = order . Id ,
CustomerId = order . CustomerId ,
Amount = order . TotalAmount
});
await _client . SendEventAsync ( eventGridEvent );
}
}
Processing Patterns
Single Event Processing
[ Function ( "ProcessStorageEvent" )]
public async Task Run (
[ EventGridTrigger ] EventGridEvent eventGridEvent ,
CancellationToken cancellationToken )
{
_logger . LogInformation (
"Processing {EventType} event for {Subject}" ,
eventGridEvent . EventType ,
eventGridEvent . Subject );
switch ( eventGridEvent . EventType )
{
case "Microsoft.Storage.BlobCreated" :
var blobData = eventGridEvent . Data
. ToObjectFromJson < StorageBlobCreatedEventData >();
await _handler . HandleBlobCreatedAsync ( blobData , cancellationToken );
break ;
case "Microsoft.Storage.BlobDeleted" :
var deletedData = eventGridEvent . Data
. ToObjectFromJson < StorageBlobDeletedEventData >();
await _handler . HandleBlobDeletedAsync ( deletedData , cancellationToken );
break ;
}
}
Batch Event Processing
[ Function ( "ProcessEventsBatch" )]
public async Task Run (
[ EventGridTrigger ] EventGridEvent [] events ,
CancellationToken cancellationToken )
{
foreach ( var evt in events )
{
await ProcessEventAsync ( evt , cancellationToken );
}
}
Event Filtering
Filter events at the subscription level (configured in Azure):
{
"filter" : {
"includedEventTypes" : [
"Microsoft.Storage.BlobCreated" ,
"Microsoft.Storage.BlobDeleted"
],
"subjectBeginsWith" : "/blobServices/default/containers/important/" ,
"subjectEndsWith" : ".json" ,
"advancedFilters" : [
{
"operatorType" : "NumberGreaterThan" ,
"key" : "data.contentLength" ,
"value" : 1024
}
]
}
}
Event Validation
Subscription Validation
Event Grid validates webhook endpoints:
[ Function ( "EventGridWebhook" )]
public async Task < HttpResponseData > Run (
[ HttpTrigger ( AuthorizationLevel . Function , "post" )]
HttpRequestData req ,
CancellationToken cancellationToken )
{
var events = await req . ReadFromJsonAsync < EventGridEvent []>( cancellationToken );
foreach ( var evt in events )
{
// Handle validation event
if ( evt . EventType == "Microsoft.EventGrid.SubscriptionValidationEvent" )
{
var validationData = evt . Data
. ToObjectFromJson < SubscriptionValidationEventData >();
var response = req . CreateResponse ( HttpStatusCode . OK );
await response . WriteAsJsonAsync ( new
{
validationResponse = validationData . ValidationCode
}, cancellationToken );
return response ;
}
// Process actual events
await _handler . HandleAsync ( evt , cancellationToken );
}
return req . CreateResponse ( HttpStatusCode . OK );
}
Error Handling & Retry
Automatic Retry
Event Grid automatically retries failed deliveries:
Retry Schedule : Exponential backoff
Maximum Attempts : 30 attempts over 24 hours
Dead Letter : Configure dead-letter destination
Dead Letter Configuration
public async Task ConfigureDeadLetterAsync ()
{
var deadLetterDestination = new StorageBlobDeadLetterDestination
{
ResourceId = "/subscriptions/.../blobServices/default" ,
BlobContainerName = "eventgrid-deadletter"
};
var eventSubscription = new EventGridSubscription
{
DeadLetterDestination = deadLetterDestination ,
EventDeliverySchema = EventDeliverySchema . EventGridSchema ,
RetryPolicy = new RetryPolicy
{
MaxDeliveryAttempts = 10 ,
EventTimeToLiveInMinutes = 1440 // 24 hours
}
};
}
Exception Handling
[ Function ( "ProcessEvent" )]
public async Task Run (
[ EventGridTrigger ] EventGridEvent eventGridEvent ,
CancellationToken cancellationToken )
{
try
{
await _handler . HandleAsync ( eventGridEvent , cancellationToken );
}
catch ( TransientException ex )
{
_logger . LogWarning ( ex , "Transient error, Event Grid will retry" );
throw ; // Let Event Grid retry
}
catch ( Exception ex )
{
_logger . LogError ( ex , "Fatal error processing event {EventId}" ,
eventGridEvent . Id );
// Log to monitoring
await _monitoring . TrackFailedEventAsync ( eventGridEvent , ex );
// Don't throw - event will be dead-lettered after max retries
}
}
Security
Managed Identity
Use managed identities for Event Grid authentication:
var credential = new DefaultAzureCredential ();
var client = new EventGridPublisherClient (
new Uri ( "https://mytopic.westus2-1.eventgrid.azure.net/api/events" ),
credential );
Access Keys
Alternatively, use access keys (less recommended):
{
"EventGrid" : {
"TopicEndpoint" : "https://mytopic.westus2-1.eventgrid.azure.net/api/events" ,
"TopicKey" : "your-access-key"
}
}
Monitoring
Application Insights
_telemetry . TrackEvent ( "EventGridEventProcessed" , new Dictionary < string , string >
{
{ "EventType" , eventGridEvent . EventType },
{ "Subject" , eventGridEvent . Subject },
{ "EventId" , eventGridEvent . Id },
{ "ProcessingTime" , stopwatch . Elapsed . ToString () }
});
Metrics to Monitor
Delivery success rate
Delivery latency
Dead-letter count
Failed delivery attempts
Event age
Common Scenarios
Blob Storage Processing
[ IntentManaged ( Mode . Merge )]
public class BlobCreatedEventHandler
: IIntegrationEventHandler < BlobCreatedEvent >
{
private readonly BlobServiceClient _blobClient ;
private readonly ILogger _logger ;
public async Task HandleAsync (
BlobCreatedEvent message ,
CancellationToken cancellationToken )
{
var blobUrl = new Uri ( message . Url );
var containerName = blobUrl . Segments [ 1 ]. TrimEnd ( '/' );
var blobName = string . Join ( "" , blobUrl . Segments . Skip ( 2 ));
var containerClient = _blobClient . GetBlobContainerClient ( containerName );
var blobClient = containerClient . GetBlobClient ( blobName );
// Download and process
var download = await blobClient . DownloadContentAsync ( cancellationToken );
await ProcessBlobContentAsync ( download . Value . Content , cancellationToken );
_logger . LogInformation ( "Processed blob {BlobName}" , blobName );
}
}
Resource Change Notifications
[ IntentManaged ( Mode . Merge )]
public class ResourceWriteSuccessHandler
: IIntegrationEventHandler < ResourceWriteSuccessEvent >
{
public async Task HandleAsync (
ResourceWriteSuccessEvent message ,
CancellationToken cancellationToken )
{
// Audit resource changes
await _auditLog . RecordChangeAsync ( new AuditEntry
{
ResourceId = message . ResourceId ,
Operation = message . OperationName ,
Timestamp = message . EventTime ,
Status = message . Status
}, cancellationToken );
}
}
Best Practices
Event Grid doesn’t guarantee order. Design handlers to be order-independent or use Event Hubs for ordered events.
Event Grid guarantees at-least-once delivery. Always implement idempotent handlers: public async Task HandleAsync ( BlobCreatedEvent evt , CancellationToken ct )
{
var processed = await _cache . GetAsync < bool >( $"event: { evt . Id } " , ct );
if ( processed )
{
_logger . LogInformation ( "Event {EventId} already processed" , evt . Id );
return ;
}
await ProcessEventAsync ( evt , ct );
await _cache . SetAsync ( $"event: { evt . Id } " , true , TimeSpan . FromDays ( 7 ), ct );
}
Plan for schema evolution:
Use semantic versioning in dataVersion
Make new fields optional
Handle multiple versions in handlers
Use advanced filters to reduce unnecessary events
Batch operations when possible
Consider consumption plan for variable loads
Local Development
Event Grid Emulator
Use the Event Grid simulator for local testing:
docker run -p 4438:80 \
-e ASPNETCORE_ENVIRONMENT=Development \
mcr.microsoft.com/azure-messaging/eventgrid-emulator
ngrok for Webhook Testing
Expose local Functions to Event Grid:
Use the ngrok URL as your Event Grid webhook endpoint.
Resources
Event Grid Triggers Official trigger documentation
Event Grid Schema Event schema reference
Event Grid Eventing Event Grid eventing module
Event Filtering Advanced filtering guide