Skip to content

06 05 Notifications Service Domain

Cyberdyne Development edited this page Feb 22, 2026 · 1 revision

Notifications Service Domain

The Notifications domain delivers alerts and events through pluggable channels (Webhook, Console). It follows the standard service domain pattern with NotificationTypes as the ServiceTypeCollection.

Channels

Channel Package Purpose
Webhook .Notifications.Webhook HTTP POST to an endpoint
Console .Notifications.Console Structured log output (dev/test)
Email .Notifications.Email SMTP email (future)

Package Structure

Services.Notifications.Abstractions/  # Interfaces, base classes, builder
Services.Notifications/              # NotificationTypes, NotificationTypeBase
Services.Notifications.Webhook/      # WebhookNotificationType + factory
Services.Notifications.Console/      # ConsoleNotificationType + factory

Registration

builder.AddFrameworkServiceTypes(loggerFactory, types =>
{
    types.AddNotifications(n =>
    {
        n.RegisterWebhook();
        n.RegisterConsole();
    });
});

Configuration

Webhook

{
  "Notifications": {
    "Webhook": [
      {
        "Name": "OrderAlerts",
        "IsEnabled": true,
        "Url": "https://hooks.example.com/notify",
        "Method": "POST",
        "ContentType": "application/json",
        "RetryCount": 3,
        "TimeoutSeconds": 30,
        "PayloadTemplate": null
      }
    ]
  }
}

WebhookNotificationConfiguration properties:

Property Default Description
Url Target URL (required)
Method POST HTTP method
ContentType application/json Request Content-Type
PayloadTemplate null Custom template (see below)
RetryCount 3 Retry attempts on transient failures
TimeoutSeconds 30 Request timeout

Console

{
  "Notifications": {
    "Console": [
      {
        "Name": "DevAlerts",
        "IsEnabled": true,
        "LogLevel": "Information"
      }
    ]
  }
}

ConsoleNotificationConfiguration properties:

Property Default Description
LogLevel Information Serilog log level for emitted messages

PayloadTemplate Token System

When PayloadTemplate is set, the webhook factory replaces tokens before sending:

Token Replaced With
{subject} NotificationRequest.Subject
{body} NotificationRequest.Message
{type} Notification type name
{timestamp} ISO 8601 UTC timestamp

When PayloadTemplate is null, the factory sends a standard JSON payload:

{
  "subject": "...",
  "body": "...",
  "type": "Webhook",
  "timestamp": "2026-02-21T12:00:00Z"
}

Example template (Slack-compatible):

{
  "PayloadTemplate": "{\"text\": \"{subject}: {body}\"}"
}

Sending Notifications

Inject IFdwServiceProvider<IGenericNotification, INotificationConfiguration> and use the builder:

public class OrderService(IFdwServiceProvider<IGenericNotification, INotificationConfiguration> notifications)
{
    public async Task NotifyOrderCompleted(string orderId, CancellationToken ct)
    {
        var request = new NotificationRequestBuilder("Webhook")
            .WithSubject("Order Completed")
            .WithMessage($"Order {orderId} has been fulfilled.")
            .WithPriority(NotificationPriority.Normal)
            .WithCorrelationId(orderId)
            .Build();

        var service = notifications.Get("OrderAlerts");
        var result = await service.Send(request, ct);
    }
}

Adding a New Channel

  1. Create a ServiceTypeOption extending NotificationTypeBase<,,>:
[ServiceTypeOption(typeof(NotificationTypes), "Teams")]
public sealed class TeamsNotificationType
    : NotificationTypeBase<INotificationService, ITeamsNotificationFactory, TeamsNotificationConfiguration>
{
    public TeamsNotificationType()
        : base("Teams", NotificationChannels.ByName("Teams"),
               "Microsoft Teams Notifications",
               "Send adaptive cards to Teams channels")
    { }

    public override IServiceCollection RegisterRequiredServices(IServiceCollection services)
    {
        services.AddSingleton<ITeamsNotificationFactory, TeamsNotificationFactory>();
        return services;
    }

    public override void RegisterFactory(IFdwServiceProvider<IGenericNotification, INotificationConfiguration> provider, IServiceProvider services)
    {
        var factory = services.GetRequiredService<ITeamsNotificationFactory>();
        provider.Register(Name, factory);

        var optionsMonitor = services.GetRequiredService<IOptionsMonitor<List<TeamsNotificationConfiguration>>>();
        provider.Register(Name, new ServiceConfigurationMonitor<TeamsNotificationConfiguration>(optionsMonitor));
    }

    public override void Configure(IServiceCollection services, IConfiguration configuration)
    {
        services.Configure<List<TeamsNotificationConfiguration>>(
            configuration.GetSection("Notifications:Teams"));
    }
}
  1. Create a [ManagedConfiguration] class and factory, following the Webhook pattern.

See Also

Clone this wiki locally