Skip to content

Notification Recipes — Workflow, Authz, Encryption

These recipes show how to combine Granit.Notifications with other framework modules for common real-world scenarios.

Workflow + Notifications: notify on state transition

Section titled “Workflow + Notifications: notify on state transition”

When an entity transitions in a workflow, publish a notification automatically. The WorkflowStateChangedEvent is published by Wolverine — handle it in a notification handler:

public static class InvoiceApprovalNotificationHandler
{
public static async Task Handle(
WorkflowStateChangedEvent @event,
INotificationPublisher publisher,
CancellationToken ct)
{
if (@event.NewState != nameof(InvoiceStatus.PendingApproval))
return;
await publisher.PublishAsync(new NotificationRequest(
Type: "InvoiceApprovalRequired",
EntityType: "Invoice",
EntityId: @event.EntityId,
Recipients: [@event.Properties["ApproverId"]],
Data: new { InvoiceNumber = @event.Properties["Number"] }), ct)
.ConfigureAwait(false);
}
}

Authorization + Notifications: permission-gated channels

Section titled “Authorization + Notifications: permission-gated channels”

Use IPermissionChecker to restrict notification channels based on the sender’s permissions (e.g., only managers can trigger SMS notifications):

public class SmsPermissionFilter(IPermissionChecker permissionChecker)
: INotificationChannelFilter
{
public async Task<bool> ShouldSendAsync(
NotificationContext context, CancellationToken ct)
{
return await permissionChecker
.IsGrantedAsync("Notifications.Sms.Send")
.ConfigureAwait(false);
}
}

Encryption + Notifications: protect PII in notification payloads

Section titled “Encryption + Notifications: protect PII in notification payloads”

When notification data contains PII (patient names, account numbers), encrypt the Data dictionary before persisting. The InApp channel stores the notification in the database — combine with IStringEncryptionService:

public class EncryptedNotificationEnricher(IStringEncryptionService encryption)
: INotificationDataEnricher
{
public Task EnrichAsync(NotificationContext context, CancellationToken ct)
{
if (context.Data.TryGetValue("PatientName", out var name))
context.Data["PatientName"] = encryption.Encrypt(name?.ToString() ?? "");
return Task.CompletedTask;
}
}

Identity + Notifications: zero-boilerplate recipient resolution

Section titled “Identity + Notifications: zero-boilerplate recipient resolution”

Apps on Granit.Identity get a deliverable pipeline without writing an IRecipientResolver. The opt-in Granit.Identity.Notifications bridge is the default path: it resolves recipient contact details straight from the identity layer — local (OpenIddict) and every federated provider (Keycloak, Entra ID, Cognito, Google) through a single adapter.

[DependsOn(typeof(GranitIdentityNotificationsModule))]
public class AppModule : GranitModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddGranitIdentityRecipientResolver();
}
}

It registers with TryAddScoped, so a custom IRecipientResolver still wins if you later need one. See Channels → ready-made resolver for the field mapping and the Identity:RecipientResolver options.

CategoryKey typesPackage
ModuleGranitNotificationsModule, GranitNotificationsEntityFrameworkCoreModule, GranitNotificationsWolverineModule
PublisherINotificationPublisher, NotificationType<TData>Granit.Notifications
ChannelsINotificationChannel, NotificationChannels, NotificationDeliveryContextGranit.Notifications
DefinitionsNotificationDefinition, INotificationDefinitionProvider, INotificationDefinitionContext, INotificationDefinitionStoreGranit.Notifications
EntitiesUserNotification, NotificationDeliveryAttempt, NotificationPreference, NotificationSubscription, UserNotificationStateGranit.Notifications
CQRSIUserNotificationReader, IUserNotificationWriter, INotificationPreferenceReader, INotificationPreferenceWriter, INotificationSubscriptionReader, INotificationSubscriptionWriter, INotificationDeliveryWriterGranit.Notifications
RecipientIRecipientResolver, RecipientInfoGranit.Notifications
Recipient resolver (Identity bridge — default path)GranitIdentityNotificationsModule, IdentityRecipientResolverOptions, AddGranitIdentityRecipientResolver()Granit.Identity.Notifications
Entity trackingITrackedEntity, TrackedPropertyConfig, EntityStateChangedData, EntityReferenceGranit.Notifications
MessagesNotificationTrigger, DeliverNotificationCommandGranit.Notifications
HandlersNotificationFanoutHandler, NotificationDeliveryHandlerGranit.Notifications
OptionsNotificationsOptions, EmailChannelOptions, SmtpOptions, BrevoOptions, ScalewayEmailOptions, SendGridEmailOptions, AcsEmailOptions, SmsChannelOptions, AcsSmsOptions, AwsSnsSmsOptions, TwilioOptions, MobilePushChannelOptions, GoogleFcmOptions, AzureNotificationHubsOptions, AwsSnsMobilePushOptions, SignalRChannelOptions, PushChannelOptions, SseChannelOptions, ZulipChannelOptions, ZulipBotOptionsvarious
EmailIEmailSender, EmailMessageGranit.Notifications.Email, Granit.Notifications.AzureCommunicationServices, Granit.Notifications.Scaleway, Granit.Notifications.SendGrid
SMSISmsSender, SmsMessageGranit.Notifications.Sms, Granit.Notifications.AwsSns, Granit.Notifications.Twilio
WhatsAppIWhatsAppSender, WhatsAppMessageGranit.Notifications.WhatsApp, Granit.Notifications.Twilio
Mobile PushIMobilePushSender, MobilePushMessage, IMobilePushTokenReader, IMobilePushTokenWriter, MobilePushTokenInfo, MobilePlatformGranit.Notifications.MobilePush, Granit.Notifications.AwsSns
SignalRNotificationHub, SignalRNotificationMessageGranit.Notifications.SignalR
Web PushIPushSubscriptionReader, IPushSubscriptionWriter, PushSubscriptionInfoGranit.Notifications.WebPush
SSEISseConnectionManager, SseConnection, SseNotificationMessageGranit.Notifications.Sse
ZulipIZulipSender, ZulipMessageGranit.Notifications.Zulip
ExceptionsNotificationDeliveryExceptionGranit.Notifications
EndpointsNotificationEndpointsOptions, MobilePushTokenEndpointsGranit.Notifications.Endpoints
ExtensionsAddGranitNotifications(), AddGranitNotificationsEntityFrameworkCore(), AddGranitNotificationsEmail(), AddGranitNotificationsEmailSmtp(), AddGranitNotificationsEmailAcs(), AddGranitNotificationsEmailScaleway(), AddGranitNotificationsEmailSendGrid(), AddGranitNotificationsBrevo(), AddGranitNotificationsSms(), AddGranitNotificationsSmsAcs(), AddGranitNotificationsSmsAwsSns(), AddGranitNotificationsTwilio(), AddGranitNotificationsWhatsApp(), AddGranitNotificationsMobilePush(), AddGranitNotificationsMobilePushGoogleFcm(), AddGranitNotificationsMobilePushAzureNotificationHubs(), AddGranitNotificationsMobilePushAwsSns(), AddGranitNotificationsSignalR(), AddGranitNotificationsPush(), AddGranitNotificationsSse(), AddGranitNotificationsZulip(), AddNotificationDefinitions<T>(), MapGranitNotifications(), MapGranitMobilePushTokens()various