OrionRelay.EntityFrameworkCore 0.5.0

dotnet add package OrionRelay.EntityFrameworkCore --version 0.5.0
                    
NuGet\Install-Package OrionRelay.EntityFrameworkCore -Version 0.5.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="OrionRelay.EntityFrameworkCore" Version="0.5.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="OrionRelay.EntityFrameworkCore" Version="0.5.0" />
                    
Directory.Packages.props
<PackageReference Include="OrionRelay.EntityFrameworkCore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add OrionRelay.EntityFrameworkCore --version 0.5.0
                    
#r "nuget: OrionRelay.EntityFrameworkCore, 0.5.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package OrionRelay.EntityFrameworkCore@0.5.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=OrionRelay.EntityFrameworkCore&version=0.5.0
                    
Install as a Cake Addin
#tool nuget:?package=OrionRelay.EntityFrameworkCore&version=0.5.0
                    
Install as a Cake Tool

OrionRelay.EntityFrameworkCore

NuGet

A durable Entity Framework Core dead-letter sink for OrionRelay. It implements the existing IDeadLetterSink over a relational table, so webhook deliveries that exhaust their attempt budget survive a process restart and are shared across instances, instead of being held in the process-local in-memory sink that loses its entries on restart.

Part of the Orion family.

What it does

  • Implements IDeadLetterSink over EF Core. The interface is not widened: this is a durable reference implementation behind the existing seam, the half of the dead-letter story the in-memory sink left open.
  • Persists the whole abandoned delivery. Each DeadLetterEntry the dispatcher routes here is stored as a DeadLetterRecord: the target endpoint, the payload, the content type and event headers a receiver would have seen, the attempt count, the final error, the last HTTP status, and the abandonment timestamp.
  • Idempotent on the delivery id. DeliveryId is the primary key, so when the dispatcher re-routes a replayed terminal delivery the second write resolves to the existing row rather than inserting a duplicate. It is the message's EventId when one was set; otherwise a surrogate keys the row, since an unidentified delivery has nothing stable to deduplicate on.
  • Exposes a read-back path for triage. GetHeldAsync returns the parked deliveries newest first (with an optional cap) and CountAsync counts them, for inspection and a later replay. These are additive queries on the concrete store, not on the IDeadLetterSink interface.
  • Provider agnostic: depends only on Microsoft.EntityFrameworkCore.Relational, so you choose the database provider (SQL Server, PostgreSQL, SQLite, and so on).

Install

dotnet add package OrionRelay.EntityFrameworkCore

You also need an EF Core provider package for your database, for example Microsoft.EntityFrameworkCore.SqlServer or Npgsql.EntityFrameworkCore.PostgreSQL.

Quick start

Register the sink before AddOrionRelay(), configuring the context inline. The bundled OrionRelayDeadLetterDbContext is ready to use:

using Moongazing.OrionRelay.EntityFrameworkCore;

// Register the durable sink first: AddOrionRelay only adds the no-op sink if no IDeadLetterSink
// is already present. This also registers a context factory the sink resolves a short-lived
// context from per abandoned delivery.
builder.Services.AddOrionRelayEntityFrameworkCoreDeadLetterSink(o =>
    o.UseSqlServer(builder.Configuration.GetConnectionString("Webhooks")));

builder.Services.AddOrionRelay(signingSecret: "whsec_your_shared_secret");

A delivery that exhausts its attempt budget is now parked in the database instead of discarded.

Inspecting held deliveries

IDeadLetterSink is write-only by design. To triage what is parked, resolve the concrete store and query it:

var sink = app.Services.GetRequiredService<EntityFrameworkCoreDeadLetterSink<OrionRelayDeadLetterDbContext>>();

var held = await sink.GetHeldAsync(limit: 100, ct);
foreach (var record in held)
{
    Console.WriteLine($"{record.DeliveryId} -> {record.Endpoint} after {record.Attempts} attempts");
}

Using your own DbContext

If you already have a context, host the dead-letter table in it by applying the configuration in OnModelCreating, then point the sink at that context:

public sealed class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.ApplyConfiguration(new DeadLetterRecordConfiguration());
        // ... your own entities
    }
}

builder.Services.AddOrionRelayEntityFrameworkCoreDeadLetterSink<AppDbContext>(o =>
    o.UseSqlServer(connectionString));

DeadLetterRecordConfiguration also accepts a custom table name if the default OrionRelayDeadLetters clashes with an existing table.

Migrations

The sink does not create the schema. Add a migration for the mapped entity the usual way and apply it as part of your deployment:

dotnet ef migrations add AddOrionRelayDeadLetters
dotnet ef database update

Versioning

Multi-targets net8.0, net9.0, and net10.0, pinning the matching EF Core major per target framework. Tracks the OrionRelay version line. See the root README and CHANGELOG.

License

Licensed under the MIT License.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.5.0 122 7/28/2026
0.4.0 110 7/20/2026