UnambitiousFx.Synapse.Generator 1.2.5

dotnet add package UnambitiousFx.Synapse.Generator --version 1.2.5
                    
NuGet\Install-Package UnambitiousFx.Synapse.Generator -Version 1.2.5
                    
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="UnambitiousFx.Synapse.Generator" Version="1.2.5">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="UnambitiousFx.Synapse.Generator" Version="1.2.5" />
                    
Directory.Packages.props
<PackageReference Include="UnambitiousFx.Synapse.Generator">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
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 UnambitiousFx.Synapse.Generator --version 1.2.5
                    
#r "nuget: UnambitiousFx.Synapse.Generator, 1.2.5"
                    
#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 UnambitiousFx.Synapse.Generator@1.2.5
                    
#: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=UnambitiousFx.Synapse.Generator&version=1.2.5
                    
Install as a Cake Addin
#tool nuget:?package=UnambitiousFx.Synapse.Generator&version=1.2.5
                    
Install as a Cake Tool

Synapse

Build Status NuGet NuGet Downloads codecov License: MIT .NET

A lightweight, high-performance mediator implementation for .NET with first-class integration with Result types.


๐Ÿ”ง Compatibility & support

  • Dependency-free at runtime: No external runtime dependencies.
  • Native AOT-compatible: Designed to work well in Native AOT scenarios (see the examples/MinimalApi).
  • Supported .NET versions: Supports Microsoft LTS releases and the latest non-LTS release. See CI matrix for exact versions.

๐ŸŽฏ Features

  • Lightweight Mediator โ€” Requests, commands, queries, and notifications with minimal allocations.
  • Result-first โ€” Uses UnambitiousFx.Functional Result for explicit error handling.
  • Streaming requests โ€” Built-in support for streaming request/response patterns.
  • Pipeline Behaviors โ€” Typed, untyped and conditional pipeline behaviors for requests and events.
  • Dependency injection friendly โ€” Register handlers and behaviours via a fluent configuration API (AddSynapse).
  • Outbox support โ€” Interfaces and helpers to implement the outbox pattern and reliable event publishing.
  • Observability hooks โ€” Metrics and tracing integration points to capture latency and publish metrics.
  • Source generator โ€” Optional code-generation to reduce allocations and simplify registration.
  • Examples & benchmarks โ€” Real-world examples and performance benchmarks included.

๐Ÿ“ฆ Installation

dotnet add package UnambitiousFx.Synapse

๐Ÿš€ Quick Start

Register mediator services

Register the synapse and your handlers in Program.cs:

builder.Services.AddSynapse(cfg =>
{
    cfg.AddRegisterGroup(new ManualRegisterGroup());

    // Request handlers
    cfg.RegisterRequestHandler<CreateTodoCommandHandler, CreateTodoCommand, Guid>()
        .RegisterRequestHandler<ListTodoQueryHandler, ListTodoQuery, IEnumerable<Todo>>();

    // Event handlers
    cfg.RegisterEventHandler<TodoUpdatedHandler, TodoUpdated>();

    // Pipeline behaviors
    cfg.RegisterRequestPipelineBehavior<SimpleLoggingBehavior>();
    cfg.RegisterEventPipelineBehavior<SimpleLoggingBehavior>();
});

Send requests

Use IInvoker to dispatch requests to handlers:

// Send a command that returns a value
var result = await invoker.InvokeAsync<CreateTodoCommand, Guid>(command);

// Send a command without a response
var result = await invoker.InvokeAsync<UpdateTodoCommand>(command);

// Stream results from an IStreamRequest
await foreach (var itemResult in invoker.InvokeStreamAsync<ListItemsRequest, Item>(request))
{
    // itemResult is Result<Item>
}

Use handlers directly

You can also resolve IRequestHandler<TRequest, TResponse> or IRequestHandler<TRequest> from DI and call HandleAsync directly when appropriate.

๐Ÿ“Š Observability & Metrics

Synapse exposes hooks for recording metrics and integrates with OpenTelemetry tracing through dedicated activity sources and metric interfaces. Consumers can provide their own ISynapseMetrics implementation or use the default which integrates with IMeterFactory.

๐Ÿ“š Documentation

Full documentation is available at https://unambitiousfx.com/lib-synapse/

๐Ÿงช Examples & Benchmarks

  • Examples are under the examples/ folder (Web API, Console, Native AOT example).
  • Benchmarks are available in benchmarks/SynapseBenchmark to measure throughput and compare against alternatives.

๐Ÿงฉ Extensibility

  • Pipeline behaviors: implement IRequestPipelineBehavior, IEventPipelineBehavior, or the typed/stream variants.
  • Registration groups: implement IRegisterGroup to modularize and share handler registration logic.
  • Outbox & commits: implement IOutboxStorage, IOutboxCommit for transactional event persistence.

Cross-assembly pipeline behaviors

An open-generic [PipelineBehavior] is applied to every request/event/stream handler the declaring assembly can see โ€” including handlers defined in referenced assemblies. The generator emits one closed (Native-AOT-safe) registration per matching handler, so a behavior registered in your composition root blankets the whole reference graph automatically. Constraints (e.g. where TRequest : ISecuredRequest) still filter which handlers a behavior wraps.

This propagation flows downward only โ€” along the reference direction. A behavior declared in a library cannot wrap a handler in an application that references it (the library cannot see that application). Place behaviors meant to apply everywhere in the composition root.

Event behaviors (IEventPipelineBehavior<TEvent>) and stream behaviors get the same treatment โ€” including where TEvent : โ€ฆ / where TRequest : โ€ฆ constraint filtering, so an open-generic event behavior constrained to a marker interface only wraps events that implement it.

CQRS boundary enforcement follows the same downward propagation. Apply [assembly: EnableSynapseCqrsBoundaryEnforcement] once at the composition root and it covers request handlers in referenced assemblies too โ€” no need to repeat the attribute in every sub-project. Leaving it on a referenced library is harmless: duplicate enforcement registrations are deduplicated at the service-collection level (the behavior is not idempotent, so this dedup is what keeps it safe).

To opt an assembly out and restrict its behaviors (and CQRS enforcement) to same-assembly handlers, apply [assembly: DisableSynapseCrossAssemblyBehaviors].

Handlers the generator cannot see โ€” those registered manually at runtime via cfg.RegisterRequestHandler<โ€ฆ>(), or living in an assembly the generator does not scan โ€” are not covered by the attribute. Enforce them explicitly with cfg.RegisterCqrsBoundaryEnforcement<TRequest>() (or the <TRequest, TResponse> overload) in the composition root. The registration is closed (Native-AOT safe) and deduplicated, so it is safe to call even for a request the generator also covers.

Ordering caveat: the Order property sorts behaviors only within a single IRegisterGroup. Across separately composed RegisterGroups (e.g. one per assembly), pipeline position follows AddRegisterGroup call order. CQRS boundary enforcement is registered "first" and stays outermost regardless.

Note: Transport/distributed messaging APIs are intentionally not documented here โ€” they may change prior to the first stable release.

๐Ÿค Contributing

We welcome contributions! Please read CONTRIBUTING.md for standards, development setup, and the PR process.

๐Ÿ“ Release notes

See releases on GitHub for detailed changelogs and version history: https://github.com/UnambitiousFx/Synapse/releases

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


Made with โค๏ธ by the UnambitiousFx team

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

  • .NETStandard 2.0

    • No dependencies.

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
1.2.5 79 7/22/2026
1.2.4 117 7/20/2026
1.2.3 103 6/28/2026
1.2.2 112 6/27/2026
1.2.1 109 6/27/2026
1.2.0 113 6/26/2026
1.1.1 124 5/23/2026
1.1.0 108 5/20/2026
1.0.0 110 5/3/2026
1.0.0-beta6 133 2/5/2026
1.0.0-beta5 119 2/5/2026
1.0.0-beta4 119 2/4/2026
1.0.0-beta3 123 1/8/2026
1.0.0-beta2 122 1/6/2026
1.0.0-beta1 121 1/6/2026