EventHighway is Standard-Compliant .NET library for event-driven programming. It is designed to be simple, lightweight, and easy to use.
Publish an event once and it fans out to every matching listener, each producing a durable delivery record you can observe, retry, archive and replay. The full V2 flow — submission, filtering, loop detection, retries (Fibonacci backoff), archiving and replay — is documented in plain language here:
📖 EventHighway V2 — Design & Flow
A Standard-compliant Blazor Server console for operating an EventHighway installation: RAG health dashboards, event/archive browsing, bulk & single-item replay, participant and secret management, and user administration.
📖 EventHighway Operations Portal — Design & User Guide
V2 Client is the latest version and should be used when possible. It is highly recommended to transition from previous versions to V2 for all new development, as support will end for older versions. The V2 client is available in the v2.11 release and later.
Note
Version 0 / Version 1 is now considered obsolete for new adoption. Emphasis is on V2 for all new development, and existing users of Version 0 / Version 1 are encouraged to upgrade to V2 to benefit from the new features.
V2 runs against SQL Server or PostgreSQL. Install the provider package of your choice
(EventHighway.SqlServer or EventHighway.PostgreSql), then construct the client with the
corresponding storage provider and configuration — the database is created and migrated
automatically on first use:
var configuration = new EventHighwayConfiguration();
// SQL Server
IClientV2 eventHighway = new EventHighwayClient(
new SqlServerStorageBrokerProvider(
"Server=.;Database=EventHighwayDB;Trusted_Connection=True;MultipleActiveResultSets=true"),
configuration).V2;
// PostgreSQL
IClientV2 eventHighway = new EventHighwayClient(
new PostgreSqlStorageBrokerProvider(
"Host=localhost;Port=5432;Database=EventHighwayDB;Username=postgres;Password=postgres"),
configuration).V2;V2 delivers events to in-process handlers — no HTTP endpoint required. Register a handler by its stable HandlerId:
var handler = new DelegateEventHandler(
id: SomeStableHandlerId,
handleAsync: (content, cancellationToken) =>
ValueTask.FromResult(new EventHandlerResult { IsSuccess = true, ResponseCode = "200" }),
name: "Students Handler");
eventHighway.RegisterEventHandler(handler);Events target an EventAddressV2 (a named channel); an EventListenerV2 subscribes a handler to that address:
DateTimeOffset now = DateTimeOffset.UtcNow;
EventAddressV2 address = await eventHighway.EventAddressV2Client
.RetrieveOrRegisterEventAddressV2Async(new EventAddressV2
{
Id = Guid.NewGuid(),
Name = "students",
Description = "Student domain events",
CreatedDate = now,
UpdatedDate = now
});
await eventHighway.EventListenerV2Client.RetrieveOrRegisterEventListenerV2Async(new EventListenerV2
{
Id = Guid.NewGuid(),
Name = "Students API Listener",
HandlerId = handler.Id,
HandlerName = handler.Name,
EventAddressV2Id = address.Id,
CreatedDate = now,
UpdatedDate = now
});A listener can optionally carry PromotedProperties + FilterCriteria so its handler only receives events that match (e.g. double.Parse(meta("Rating")) >= 8.0).
await eventHighway.EventV2Client.SubmitEventV2Async(new EventV2
{
Id = Guid.NewGuid(),
EventAddressV2Id = address.Id,
EventName = "StudentRegistered",
Content = "{ \"studentId\": 123 }",
// omit ScheduledDate for immediate dispatch; set it for a scheduled event
CreatedDate = now,
UpdatedDate = now
});
IQueryable<ListenerEventV2> deliveries =
await eventHighway.ListenerEventV2Client.RetrieveAllListenerEventV2sAsync();A published EventV2 produces one ListenerEventV2 delivery record per matching listener — each with a Status (Pending / Success / Error / Replay) and the handler's response. Scheduled events wait until you call FireScheduledPendingEventV2sAsync(). Events may be attributed to an EventParticipantV2 and authorized with a participant secret.
Runnable, end-to-end samples and in-depth guides:
| Sample | Description |
|---|---|
| EventHighway V2 — Design & Flow | Plain-language walkthrough of submit, dispatch, filtering, loop detection, retries, archiving and replay |
EventHighway.ClientV2.BasicApp |
A complete console sample: register handlers, publish immediate & scheduled events, filtering, loop detection, targeted replay, and a health summary |
EventHighway.ClientV2.SubstrateApp |
A service-to-service (in-process substrate) sample using the same V2 client |
Legacy
V1guides remain underEventHighway.Core/Resources/CodeSamples/V1for existing users, but new development should targetV2.
Everyone is welcome to contribute — whichever way suits you best:
- Suggest — log a feature request or bug report under Issues.
- Build — pick up an open feature request and help with development.
- Verify — help with testing, reviewing pull requests, or hardening acceptance coverage.
All contributions follow The Standard — test-driven, one layer at a time.
EventHighway ships two storage providers — SQL Server and PostgreSQL — and both must stay schema-identical. If your change touches the database (new entity, new column, index, etc.), you must add a matching EF Core migration to both provider projects:
| Provider | Project |
|---|---|
| SQL Server | EventHighway.SqlServer |
| PostgreSQL | EventHighway.PostgreSql |
Each provider project contains its own design-time context factory, so migrations are generated directly against the provider project. By default the factories target a local database ((localdb)\MSSQLLocalDB for SQL Server, localhost:5432 for PostgreSQL); set the CONNECTION_STRING environment variable to override.
From the solution root:
# SQL Server
dotnet ef migrations add <YourMigrationName> --project EventHighway.SqlServer --startup-project EventHighway.SqlServer
# PostgreSQL
dotnet ef migrations add <YourMigrationName> --project EventHighway.PostgreSql --startup-project EventHighway.PostgreSql# SQL Server
Add-Migration <YourMigrationName> -Project EventHighway.SqlServer -StartupProject EventHighway.SqlServer
# PostgreSQL
Add-Migration <YourMigrationName> -Project EventHighway.PostgreSql -StartupProject EventHighway.PostgreSqlUse the same migration name for both providers, and include both generated migrations (plus the updated model snapshots) in your pull request. The CI build runs acceptance tests against both providers, so a missing migration on either side will fail the build.
EventHighway is an officially released, Standard-Compliant Pub/Sub core library that can be deployed within an API or any Console Application. It is intentionally platform-agnostic so it can process events from anywhere to anywhere. V2 is an in-process event bus with durable delivery records, moving well beyond the original fire-and-forget model.
Current V2 capabilities include:
- In-Process Handlers — deliver events to registered
IEventHandlercode byHandlerId; no HTTP endpoint required. - Immediate & Scheduled Events — instant dispatch, or time-deferred delivery fired by
FireScheduledPendingEventV2sAsync. - Filtering & Promoted Properties — optional - listeners receive only events matching their
FilterCriteriaif specified. - Delivery Observability — one
ListenerEventV2per event listener withPending/Success/Error/Replaystatus and the handler's response. - Loop Detection & Quarantine — configurable thresholds guard against runaway republishing.
- Participants & Secrets — attribute and authorize events to an
EventParticipantV2via rotating secrets. - Retries — listener-level budgets with incremental (Fibonacci) backoff for resilient delivery.
- Archiving & Replay — processed events are archived, then replayed in bulk or to a targeted listener for back-fill.
- Pluggable Storage Providers — anything implementing the storage-provider contract; SQL Server and PostgreSQL ship today.
- Operations Portal — a Standard-compliant Blazor Server console for operating an installation (§0.2):
- Health dashboards — RAG status board (live) plus statistics dashboards (traffic, usage by address/participant, retries, loops, duplicates).
- Events — browse and inspect event content; archive processed events.
- Archived events — browse, purge by date, and replay a single item from its detail view.
- Bulk replay — re-deliver archived events scoped by address, listener, and/or date range.
- Event participants & secrets — manage participants and add/rotate/revoke their secrets.
- Event addresses & listeners — register and manage addresses and their listeners.
- User administration — roles, lockout, 2FA, disable/delete, and email-confirmation / password-reset links.
- User ↔ participant associations — link users to participants (from both the user and participant screens).
- Self-service (My Account → Participant Management) — association-scoped, read-only participant view with secret self-management; no admin bypass.
This library was built according to The Standard. The library follows engineering principles, patterns and tooling as recommended by The Standard.
This library is also a community effort which involved many nights of pair-programming, test-driven development and in-depth exploration research and design discussions.
The most important fulfillment aspect in a Standard compliant system is aimed towards contributing to people, its evolution, and principles. An organization that systematically honors an environment of learning, training, and sharing knowledge is an organization that learns from the past, makes calculated risks for the future, and brings everyone within it up to speed on the current state of things as honestly, rapidly, and efficiently as possible.
We believe that everyone has the right to privacy, and will never do anything that could violate that right. We are committed to writing ethical and responsible software, and will always strive to use our skills, coding, and systems for the good. We believe that these beliefs will help to ensure that our software(s) are safe and secure and that it will never be used to harm or collect personal data for malicious purposes.
The Standard Community as a promise to you is in upholding these values.
A special thanks to all the community members, and the following dedicated engineers for their hard work and dedication to this project.
Mr. Hassan Habib
Mr. Christo du Toit
Mr. Zafar Urakov
Mr.Abdulsamad Osunlana
Mr.Nodirkhan Abdumurotov
Mr.Kailu Hu
Mr.Greg Hays
Mr.Ahmad Salim

