Optima.Net.Events 1.0.7

Prefix Reserved
dotnet add package Optima.Net.Events --version 1.0.7
                    
NuGet\Install-Package Optima.Net.Events -Version 1.0.7
                    
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="Optima.Net.Events" Version="1.0.7" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Optima.Net.Events" Version="1.0.7" />
                    
Directory.Packages.props
<PackageReference Include="Optima.Net.Events" />
                    
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 Optima.Net.Events --version 1.0.7
                    
#r "nuget: Optima.Net.Events, 1.0.7"
                    
#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 Optima.Net.Events@1.0.7
                    
#: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=Optima.Net.Events&version=1.0.7
                    
Install as a Cake Addin
#tool nuget:?package=Optima.Net.Events&version=1.0.7
                    
Install as a Cake Tool

Optima.Net.Events

A schema-driven event serialization framework for .NET supporting Avro and Protobuf.

Optima.Net.Events provides deterministic schema generation, schema-hash validation, and payload normalization to ensure safe event exchange between distributed systems.

If you like what I built here or it helped you learn something new, please consider buying me a coffee:
https://buymeacoffee.com/snamretsuek

Your support is greatly appreciated!


Overview

Optima.Net.Events enables schema-safe event exchange between microservices using either Avro or Protobuf.

The library focuses on:

  • deterministic schema generation
  • schema hash validation
  • payload normalization
  • transport independence
  • compatibility across service versions

This ensures events remain forward and backward compatible across services.


Architecture Overview

The library is intentionally structured around a small set of clear responsibilities.

IPayload
   ?
Payload (base implementation)
   ?
DynamicPayload (runtime payload convenience)
   ?
GenericEvent<TPayload> (event envelope)
   ?
Schema Generators
   ??? AvroSchemaGenerator
   ??? ProtobufSchemaGenerator
   ?
Serializers
   ??? AvroEventSerializer
   ??? ProtobufEventSerializer

Infrastructure depends only on the IPayload contract, not specific implementations.


Event Envelope

All events are wrapped in a single generic envelope.

GenericEvent<TPayload>

The envelope contains:

  • EventId
  • EventType
  • Source
  • Timestamp
  • SchemaVersion
  • SchemaHash
  • CausationEventId
  • CorrelationId
  • DeDuplicationId
  • StreamId
  • Payload

This envelope is transport agnostic and can be used with:

  • Kafka
  • RabbitMQ
  • Azure Service Bus
  • EventStoreDB
  • HTTP event streaming

Payload Model

Payloads implement the contract:

public interface IPayload
{
    string PayloadName { get; }
    IReadOnlyDictionary<string, object> Fields { get; }
}

The library provides a base implementation:

public abstract class Payload : IPayload

The base class guarantees:

  • consistent field storage
  • deterministic schema generation
  • normalized field names
  • fluent payload construction

Runtime Payload Example

var payload = new DynamicPayload("PaymentRequested")
    .Add("SourceAccountNumber", "123456")
    .Add("TargetAccountNumber", "987654")
    .Add("Amount", 1500.75)
    .Add("Currency", "USD");

DynamicPayload is a convenience class that allows runtime payload creation.


Declared Payload Example

public class PaymentRequestedPayload : Payload
{
    public PaymentRequestedPayload(decimal amount, string currency)
        : base(nameof(PaymentRequestedPayload))
    {
        Add("Amount", amount);
        Add("Currency", currency);
    }
}

Declared payloads provide stronger domain modelling and clearer contracts.


Avro Serialization Example

var payload = new DynamicPayload("PaymentRequested")
    .Add("Amount", 1500.75)
    .Add("Currency", "USD");

var evt = new GenericEvent<DynamicPayload>
{
    Source = "PaymentsService",
    SchemaVersion = "V1.0.0",
    Payload = payload
};

var schema = AvroSchemaGenerator.GenerateSchemaFromGenericEvent(evt);

var bytes = AvroEventSerializer.Serialize(evt, schema);

var result = AvroEventSerializer.Deserialize(bytes, schema);

Protobuf Serialization Example

var payload = new DynamicPayload("PaymentRequested")
    .Add("Amount", 1500.75)
    .Add("Currency", "USD");

var evt = new GenericEvent<DynamicPayload>
{
    Source = "PaymentsService",
    SchemaVersion = "V1.0.0",
    Payload = payload
};

var schema = ProtobufSchemaGenerator.GenerateSchemaProto(
    payload.Fields,
    payload.PayloadName
);

var bytes = ProtobufEventSerializer.Serialize(evt, schema);

var result = ProtobufEventSerializer.Deserialize(bytes, schema);

Deterministic Schema Generation

Both schema generators ensure stable ordering of fields.

This guarantees:

  • identical payloads always produce identical schemas
  • schema hashes remain stable
  • distributed systems cannot drift accidentally

This is critical for schema-hash validation.


Schema Hash Validation

During serialization a SHA256 schema hash is computed.

During deserialization the hash is validated to ensure:

  • the correct schema was used
  • schemas have not changed
  • event integrity is preserved

Event Lifecycle

Typical lifecycle of an event using this library:

Domain creates payload
        ?
Payload wrapped in GenericEvent
        ?
Schema generated
        ?
Event serialized
        ?
Event transported
        ?
Event received
        ?
Schema hash validated
        ?
Payload reconstructed

Automatic Payload Discovery

Payloads can be automatically discovered by scanning domain assemblies.

Example DI setup:

services.AddEventPayloadDiscovery(
    typeof(SomeDomainPayload).Assembly
);

Discovery enables tooling such as:

  • automatic schema generation
  • event catalogs
  • compatibility checks
  • documentation generation

CLI Schema Generation

It is recommended to implement a small CLI tool that scans assemblies and generates schemas.

Example:

dotnet run -- generate-schemas --assembly MyDomain.dll

This allows teams to:

  • version schemas
  • publish schemas to a registry
  • validate schema evolution in CI pipelines

Example Clean Architecture layout:

MySystem.Domain
    Payloads
    Aggregates
    Domain Events

MySystem.Application
    DI setup
    Event publishing

MySystem.Infrastructure
    Optima.Net.Events integration
    Schema management

Payload discovery should be triggered in the Application layer by scanning the Domain assembly.


Comparison

Feature Avro Protobuf


Schema format JSON (.avsc) Text (.proto) Runtime flexibility High Medium Performance Fast Very fast Schema evolution Native support Manual numbering Payload model Dynamic or declared Dynamic dictionary

Performance depends heavily on payload structure and runtime environment.

Always run your own benchmarks.


Optional Envelope Pattern

Optima.Net.Events does not enforce a transport envelope.

However many systems wrap events in something like:

public sealed record EventEnvelope<TEvent>(
    Guid EventId,
    DateTimeOffset Timestamp,
    string SchemaHash,
    TEvent Payload);

This allows:

  • retrieving schemas via SchemaHash
  • validating events before deserialization
  • consistent event metadata recording

Compatibility

  • .NET 8.0 or later
  • Windows
  • Linux
  • macOS

License

MIT License � 2025

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 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 was computed.  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 (1)

Showing the top 1 NuGet packages that depend on Optima.Net.Events:

Package Downloads
Optima.Net.DomainModel

Optima.Net.DomainModel Defines the immutable structural foundation of the domain, enforcing invariants and preventing illegal domain states without handling behavior, workflows, or persistence.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.7 105 3/4/2026
1.0.6 116 1/17/2026
1.0.5 154 1/8/2026
1.0.4 120 1/8/2026
1.0.3 467 11/19/2025
1.0.2 294 11/12/2025
1.0.1 287 11/12/2025
1.0.0 276 11/10/2025

RELEASENOTES.md