Eigenverft.WebLib.SerilogRelayReceiver
1.0.0.8
dotnet add package Eigenverft.WebLib.SerilogRelayReceiver --version 1.0.0.8
NuGet\Install-Package Eigenverft.WebLib.SerilogRelayReceiver -Version 1.0.0.8
<PackageReference Include="Eigenverft.WebLib.SerilogRelayReceiver" Version="1.0.0.8" />
<PackageVersion Include="Eigenverft.WebLib.SerilogRelayReceiver" Version="1.0.0.8" />
<PackageReference Include="Eigenverft.WebLib.SerilogRelayReceiver" />
paket add Eigenverft.WebLib.SerilogRelayReceiver --version 1.0.0.8
#r "nuget: Eigenverft.WebLib.SerilogRelayReceiver, 1.0.0.8"
#:package Eigenverft.WebLib.SerilogRelayReceiver@1.0.0.8
#addin nuget:?package=Eigenverft.WebLib.SerilogRelayReceiver&version=1.0.0.8
#tool nuget:?package=Eigenverft.WebLib.SerilogRelayReceiver&version=1.0.0.8
Eigenverft.WebLib.SerilogRelayReceiver
ASP.NET Core receiver for Eigenverft.NetLib.SerilogRelay batches.
The package provides:
- HTTP ingestion and protocol validation for SerilogRelay batches;
- optional endpoint-scoped bearer-token authentication;
- built-in durable persistence through Entity Framework Core;
- provider-neutral storage integration: the host chooses SQLite, SQL Server, PostgreSQL/Npgsql, or another compatible EF Core provider;
- a custom
ISerilogRelayBatchHandlerpath for queue, multi-backend, or non-EF scenarios.
Supported frameworks
- .NET 8 (
net8.0) - .NET 10 (
net10.0)
The package references the matching major version of Microsoft.EntityFrameworkCore. It does not reference a concrete database provider.
Install
dotnet add package Eigenverft.WebLib.SerilogRelayReceiver
Add the EF Core provider package selected by the host separately.
EF Core quick start
Define a host-owned DbContext and include the receiver model:
public sealed class LoggingDbContext : DbContext
{
public LoggingDbContext(DbContextOptions<LoggingDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ConfigureSerilogRelayReceiver();
}
}
Register an IDbContextFactory<TDbContext> with the provider selected by the host. SQLite is shown only as an example:
builder.Services.AddDbContextFactory<LoggingDbContext>(
options => options.UseSqlite(
builder.Configuration.GetConnectionString("Logging")));
builder.Services
.AddSerilogRelayReceiverEntityFrameworkCore<LoggingDbContext>();
Map the receiver endpoint:
app.MapSerilogRelayReceiverEntityFrameworkCore<LoggingDbContext>(
"/api/v1/logs",
options =>
{
options.BearerToken =
builder.Configuration["SerilogRelay:BearerToken"];
options.MaximumBatchEvents = 100;
});
The built-in handler creates and disposes one isolated DbContext per accepted batch. Its SaveChangesAsync therefore cannot accidentally persist unrelated tracked changes from another request scope.
Changing the host's AddDbContextFactory provider configuration is enough to use another EF Core provider. Provider packages, connection strings, migrations, retention, and database lifecycle remain host-owned.
EF Core model and migrations
ConfigureSerilogRelayReceiver() adds the public SerilogRelayReceivedEvent entity to the host model.
For relational providers the default table name is:
SerilogRelayReceivedEvents
Important model semantics:
ReceiveIdis the receiver-local generated primary key;EventIdis indexed but deliberately not unique;- repeated delivery therefore creates another physical receive instead of being rejected or silently discarded;
- the model also indexes
BatchId,ReceivedAtUtc, and(ApplicationId, ReceivedAtUtc). - payload text fields preserve
nulland empty strings as distinct values;BatchTimestamp,Timestamp,Level,RenderMessage, andMessageTemplateare nullable, as are the optional machine, tracing, exception, and property fields.
The receiver does not ship provider-specific migrations. Because the entity is part of the host's DbContext model, the host's normal EF Core migration workflow owns schema creation and upgrades.
Existing databases created with the earlier non-nullable model need a host-owned migration allowing NULL in BatchTimestamp, Timestamp, Level, RenderMessage, and MessageTemplate. Updating the package or calling EnsureCreated() does not change an existing table.
For temporary/test databases, EnsureCreated() can be useful. Production databases that use migrations should use the host's normal migration workflow instead of mixing migrations with EnsureCreated().
Sender and receiver responsibilities
This package is a matching receiver implementation, not a required peer of Eigenverft.NetLib.SerilogRelay. Either side can be implemented independently against the wire format and HTTP acknowledgment contract.
The sender handles bounded local buffering, outage retries, backlog delivery during normal operation, and bounded shutdown delivery. Any HTTP 2xx allows it to release the acknowledged events locally. It does not require a receiver-side persistence receipt or negotiate storage and payload limits.
The receiver owns its acceptance policy. The built-in EF Core handler saves every validated event before returning successfully. A custom handler or independently implemented receiver may forward, filter, or deliberately discard an event and still acknowledge it, for example when its policy excludes oversized events. Such acknowledgment is an intentional receiver decision; the sender will not retry those events. A non-2xx response keeps them pending for the sender's retry policy.
The sender's configurable 4 MiB batch target does not impose a limit on this receiver. A single event above that target can arrive in its own batch. Host/proxy request limits and receiver acceptance policy remain host concerns.
Durable acceptance semantics
The built-in EF Core handler:
- creates a fresh host-configured DbContext for each accepted batch;
- maps every validated event to one
SerilogRelayReceivedEvent; - preserves the current batch and event metadata;
- adds receiver-side
ReceivedAtUtc; - adds the complete batch to the DbContext;
- calls
SaveChangesAsynconce; - returns successfully only after that save completes.
For normal relational EF Core providers, the provider/EF Core transaction semantics protect one SaveChanges operation. The receiver test suite verifies with SQLite that a failure while persisting a later event leaves no rows from the batch.
A production provider must offer durability and atomicity appropriate for the endpoint contract. Provider-specific behavior remains the host's responsibility.
Endpoint and storage topology
An endpoint is not tied to one ApplicationId. A valid batch may contain events from multiple applications, machines, and processes.
The built-in EF Core integration directly supports:
| Topology | Configuration |
|---|---|
| 1 endpoint → 1 storage | one mapped EF Core endpoint and one DbContext |
| n endpoints → 1 storage | multiple mappings using the same DbContext |
| n endpoints → n storages | mappings using different DbContext types/providers |
A single endpoint can target multiple durable backends through a custom ISerilogRelayBatchHandler. The receiver does not impose a distributed transaction protocol for that case.
Application-based storage routing, application allow-lists, and storage partitioning are not part of the 1.0 API.
Request ownership and cancellation
Before a complete batch has been received and validated, request processing uses HttpContext.RequestAborted.
After validation, durable handling receives the host application's stopping token instead of the client request-abort token. Consequently:
- a client disconnect after durable handoff does not by itself cancel persistence;
- host shutdown can cancel in-flight durable work;
- host-shutdown cancellation returns
503 Service Unavailable; - successful durable completion returns
204 No Content.
Endpoint options
SerilogRelayReceiverOptions intentionally contains only:
BearerToken: optional exact bearer token; null/empty/whitespace disables token validation;MaximumBatchEvents: maximum accepted event count, default100.
Options belong to each mapped endpoint, so different endpoints can use different authentication and limits.
Wire protocol behavior
The receiver validates:
- protocol version
1; - canonical GUID
BatchId; Countmatching the number of events;MaximumBatchEvents;- no
nullentries inLogs; - canonical GUID
EventId; - non-empty
ApplicationId; - positive
ProcessId.
SerilogRelay wire JSON is deserialized with receiver-owned ASP.NET Web-compatible JSON settings. Global host HttpJsonOptions therefore cannot silently change the relay protocol's naming or case behavior.
HTTP results:
204: durable handling completed;400: malformed or protocol-invalid payload;401: bearer authentication failed;415: unsupported JSON media type or charset;503: durable handling was cancelled because the host is stopping;- other
5xx: unexpected receiver, handler, or storage failure.
Custom handler path
Applications that need queue-backed acceptance, multiple durable backends, or non-EF processing can supply their own handler:
builder.Services.AddSerilogRelayReceiver<MyRelayBatchHandler>();
app.MapSerilogRelayReceiver<MyRelayBatchHandler>(
"/api/v1/logs");
A custom handler must complete its chosen acceptance policy before returning successfully. If that policy promises durable storage or queue handoff, it must fulfill that promise before acknowledgment. Intentional filtering or discarding also completes acceptance and allows the sender to release those events.
Not part of the 1.0 contract
The receiver intentionally does not define:
- request-body byte limits;
- application allow-lists or application-based storage routing;
- retention/cleanup policy;
- duplicate-query or deduplicated-view behavior;
- provider-specific migrations;
- multi-backend composition helpers;
- richer acknowledgement payloads.
| Product | Versions 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 was computed. 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. |
-
net10.0
- Microsoft.EntityFrameworkCore (>= 10.0.12)
-
net8.0
- Microsoft.EntityFrameworkCore (>= 8.0.31)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
1.0.0 establishes the first stable Eigenverft SerilogRelay receiver contract.
- Targets .NET 8 and .NET 10.
- Provides ASP.NET Core SerilogRelay ingestion with endpoint-scoped bearer authentication, batch-size limits, protocol validation, and receiver-owned wire JSON behavior.
- Adds provider-neutral Entity Framework Core persistence while leaving the concrete database provider, connection string, migrations, retention, and database lifecycle to the host.
- Adds SerilogRelayReceivedEvent and ConfigureSerilogRelayReceiver() for host-owned DbContext model integration.
- Adds AddSerilogRelayReceiverEntityFrameworkCore<TDbContext>() and MapSerilogRelayReceiverEntityFrameworkCore<TDbContext>(); the built-in handler uses a host-registered IDbContextFactory<TDbContext> and one isolated DbContext per batch.
- Persists the complete batch with one SaveChangesAsync call and returns 204 only after durable handling completes.
- Preserves null and empty payload text separately in the wire contract and EF Core storage. Existing databases require a host migration to make BatchTimestamp, Timestamp, Level, RenderMessage, and MessageTemplate nullable.
- Keeps EventId non-unique so retries/repeat delivery are preserved as additional physical receives rather than rejected as conflicts.
- Keeps durable work independent from client disconnect after validated handoff while allowing host shutdown to cancel in-flight handling with 503.
- Supports batches containing multiple ApplicationId values and multiple endpoint mappings with independent options.
- Retains custom ISerilogRelayBatchHandler support for queue-backed, multi-backend, or non-EF durable handling.