Delivery Log Middleware
The middleware is an IEventMiddleware registered via EventPublisherBuilder.Use<T>(). It sits in the publisher pipeline and records every publish attempt.
How It Works
On every publish call, the middleware:
- Captures start time — Uses
IEventSystemTime.UtcNowas the start time - Reads attempt number — From
EventContext(initializes to 2 on first call, returns 1) - Executes pipeline — Calls
next(context) - Records outcome:
- On success:
Outcome = Succeeded - On exception:
Outcome = Failed, captures error details, re-throws exception
- On success:
- Writes record — Constructs
EventDeliveryRecordand callsIEventPublishDeliveryLog.RecordAsync()
Key Characteristics
| Characteristic | Description |
|---|---|
| Never swallows exceptions — The middleware always re-throws publish failures | |
| Storage failures are logged — If the log write itself fails, the exception is logged and swallowed | |
Uses time abstraction — IEventSystemTime instead of DateTimeOffset.UtcNow for testability | |
Tracks attempt number — Via EventContext for retry scenarios |
Time Abstraction
Using IEventSystemTime instead of direct DateTimeOffset.UtcNow calls makes timestamps deterministic in tests:
public class FrozenSystemTime : IEventSystemTime
{
public DateTimeOffset UtcNow { get; } = new DateTimeOffset(2025, 6, 1, 12, 0, 0, TimeSpan.Zero);
}
// In tests:
services.AddSingleton<IEventSystemTime, FrozenSystemTime>();
Registration
builder.Services
.AddEventPublisher()
.AddDeliveryLog(log => log.UseInMemory());
The middleware is automatically added to the publisher pipeline when you call AddDeliveryLog().