Orchard Core Omnichannel Azure Event Grid
Configure Event Grid Ingestion
You are an Orchard Core expert. Configure secure Azure Event Grid ingestion for the CrestApps Omnichannel pipeline, and implement handlers only for the events your application understands.
Guidelines
- Install
CrestApps.OrchardCore.Omnichannel.EventGridin the web/startup project. - Enable the base Omnichannel feature and the exact Event Grid feature ID
CrestApps.OrchardCore.Omnichannel.EventGrid. - The module exposes an anonymous
POSTendpoint atOmnichannel/webhook/AzureEventGrid; it disables antiforgery because Azure Event Grid cannot supply an Orchard antiforgery token. - Prefer a valid Microsoft Entra bearer token for Event Grid delivery. A configured
aeg-sas-keyrequest header is a supported shared-secret alternative. Do not expose an unauthenticated public webhook. - Configure all three AAD settings when using bearer authentication. A partial AAD configuration cannot validate a token and the request is rejected.
- Keep SAS keys and token configuration in user secrets, Key Vault, or environment-specific configuration. Never place a production secret in a recipe or source file.
- The endpoint accepts Event Grid event arrays and rejects request bodies larger than 1 MiB with HTTP 413.
- The module saves each normal event as an inbound
OmnichannelMessagein theOmnichannelYesSql collection, then invokes every registeredIOmnichannelEventHandler. - Event Grid payload normalization is deliberately generic. It checks common
data names such as
from,to,content,channel, andtimestamp; a channel-specific handler should interpret provider-specific data.
Feature and Package
| Item | Value |
|---|---|
| NuGet package | CrestApps.OrchardCore.Omnichannel.EventGrid |
| Base feature | CrestApps.OrchardCore.Omnichannel |
| Event Grid feature | CrestApps.OrchardCore.Omnichannel.EventGrid |
| Webhook route | POST /Omnichannel/webhook/AzureEventGrid |
Install the package in the web/startup project, then enable it with a recipe:
{
"steps": [
{
"name": "Feature",
"enable": [
"CrestApps.OrchardCore.Omnichannel",
"CrestApps.OrchardCore.Omnichannel.EventGrid"
],
"disable": []
}
]
}
Configure Webhook Authentication
The feature binds EventGridOptions from
CrestApps:Omnichannel:EventGrid in tenant configuration.
{
"CrestApps": {
"Omnichannel": {
"EventGrid": {
"EventGridSasKey": "${EVENT_GRID_SAS_KEY}",
"AADIssuer": "https://sts.windows.net/<tenant-id>/",
"AADAudience": "api://<application-id>",
"AADMetadataAddress": "https://login.microsoftonline.com/<tenant-id>/.well-known/openid-configuration"
}
}
}
}
EventGridOptions property |
Use |
|---|---|
EventGridSasKey |
Fixed-time comparison against the aeg-sas-key header |
AADIssuer |
Expected issuer for bearer token validation |
AADAudience |
Expected audience for bearer token validation |
AADMetadataAddress |
OpenID Connect metadata source for signing keys |
Prefer Microsoft Entra delivery for production:
- For Entra delivery, set
AADIssuer,AADAudience, andAADMetadataAddress, then configure Event Grid token delivery to match. - For shared-key delivery, set
EventGridSasKeyand configure Event Grid to send the same value inaeg-sas-key. - A request is authorized as soon as either configured mechanism succeeds.
Create the Event Subscription
- Enable the feature and deploy the public HTTPS endpoint first.
- In Azure Event Grid, create an event subscription with Webhook delivery.
- Set its target to
https://<host>/Omnichannel/webhook/AzureEventGrid. - Configure the selected authentication mechanism.
- Let Event Grid send its validation event before publishing application events.
- Monitor HTTP 401, HTTP 400, and HTTP 413 responses in the application logs.
Subscription Validation Flow
Event Grid sends an event whose type is
Microsoft.EventGrid.SubscriptionValidationEvent. The endpoint reads
SubscriptionValidationEventData.ValidationCode and responds with:
{
"validationResponse": "<validation-code>"
}
Do not register a custom IOmnichannelEventHandler to answer this handshake.
The endpoint handles it before persistence and event-handler dispatch.
Inbound Event Processing
For every non-validation EventGridEvent, AzureEventGridEndpoint:
- Creates an inbound
OmnichannelMessage. - Reads common fields from the event data where they exist.
- Falls back to preserving raw event JSON as message content when parsing fails.
- Stores the message in
OmnichannelConstants.CollectionName. - Creates an
OmnichannelEventwith the Event Grid ID, event type, subject, binary data, and stored message. - Invokes registered
IOmnichannelEventHandlerimplementations.
This endpoint does not map a provider event to a particular channel processor. Use an event handler to recognize event types and validate the provider payload before applying business behavior.
Implement a Channel-Specific Handler
Implement IOmnichannelEventHandler in the consuming module and ignore events
outside its scope. Keep the handler sealed and use a file-scoped namespace.
using CrestApps.OrchardCore.Omnichannel.Core;
using CrestApps.OrchardCore.Omnichannel.Core.Models;
namespace MyCompany.OrchardCore.Communications;
public sealed class ProviderEventHandler : IOmnichannelEventHandler
{
public Task HandleAsync(OmnichannelEvent omnichannelEvent, CancellationToken cancellationToken = default)
{
if (!string.Equals(omnichannelEvent.EventType, "Contoso.SmsReceived", StringComparison.Ordinal))
{
return Task.CompletedTask;
}
// Validate and process the provider-specific payload here.
return Task.CompletedTask;
}
}
Register it with the appropriate Orchard Core lifetime in the consuming feature. Event Grid invokes all registered handlers, so handlers must filter by event type, channel, direction, or provider data before acting.
Operational and Security Checklist
- Use HTTPS and a publicly reachable route for the Event Grid subscription.
- Do not treat successful Event Grid authentication as provider-payload validation when multiple publishers share a topic.
- Log only non-sensitive identifiers; do not log body content, SAS keys, or bearer tokens.
- Keep event handlers idempotent because Event Grid delivery can be retried.
- Treat
Channel = "Unknown"as a signal that provider data needs explicit mapping in a handler. - Keep the payload under 1 MiB or store large content externally and publish a reference event.
- Test subscription validation, an authorized application event, a missing credential, and malformed JSON before production rollout.