Skip to content

Notifications

Notifications are hooks raised by the system indicating that something has happened. Notifications are always past-tense, and cannot be used to cancel or prevent an action from happening. They are used for informing other parts of the system that something has occurred. Handling notifications is a way to decouple the system.

Creating Notifications

Since these are notifications that something happened, notifications should be named with the pattern {Noun}{Past Tense Verb}Notification, e.g. DocumentCreatedNotification, UserDisabledNotification.

Notifications should always be public record types, but they have no inheritance requirements.

Notifications should include all the information needed to handle the notification. For example, if a DocumentCreatedNotification is raised, it should include the Document that was created and the IPrincipal that raised the notification. The IPrincipal is important for auditing and security purposes and should be included as the last parameter on all notifications.

Notification Handlers

Notification handlers should implement the INotificationHandler<TNotification> interface. A notification handler should be named in the pattern “{ActionPerformed}{NotificationType}Handler”.

For example, a handler that will email an employee’s manager when the employee’s raise has been approved should be named something like EmailManagerRaiseApprovedNotificationHandler. “EmailManager” represents the action being performed in the handler. “RaiseApprovedNotification” is the event this handler is acting on. “Handler” is a constant that all handler names end with.

Since handlers are implementation service classes for the purposes of dependency injection, they should be internal and sealed.

Examples

Notification

public record DocumentCreatedNotification(Document Document, IPrincipal RaisedBy);
public record UserDisabledNotification(User User, IPrincipal RaisedBy);
public record EmployeeUpdatedNotification(Employee Employee, IReadOnlyList<FieldChange> FieldChanges, IPrincipal RaisedBy);

Notification Handler

internal sealed class EmailAuthorDocumentCreatedNotificationHandler(IMediator mediator) : INotificationHandler<DocumentCreatedNotification>
{
public async Task Handle(DocumentCreatedNotification notification, CancellationToken cancellationToken)
{
Response sendEmail = await mediator.Send(new SendEmailCommand(notification.Document.CreatedBy, "Document Created", "Your document has been created."), cancellationToken);
sendEmail.ThrowIfUnsuccessful();
}
}