VitalRouter 2.2.0
dotnet add package VitalRouter --version 2.2.0
NuGet\Install-Package VitalRouter -Version 2.2.0
<PackageReference Include="VitalRouter" Version="2.2.0" />
<PackageVersion Include="VitalRouter" Version="2.2.0" />
<PackageReference Include="VitalRouter" />
paket add VitalRouter --version 2.2.0
#r "nuget: VitalRouter, 2.2.0"
#:package VitalRouter@2.2.0
#addin nuget:?package=VitalRouter&version=2.2.0
#tool nuget:?package=VitalRouter&version=2.2.0
VitalRouter
VitalRouter is a high-performance, zero-allocation in-memory messaging library for C#. It is specifically designed for environments where performance and decoupling are critical, such as Unity games or complex .NET applications.
By using simple attributes, you can implement asynchronous handlers, middleware (interceptors), and advanced sequence control. VitalRouter leverages Roslyn Source Generators to produce highly efficient code, promoting a clean, unidirectional control flow with minimal overhead.
Documentation
Visit vitalrouter.hadashikick.jp to see the full documentation.
Key Features
- Zero Allocation: Optimized for high-frequency messaging without GC pressure.
- Thread-Safe: Designed for safe use across multiple threads.
- Unidirectional Flow: Promotes a predictable data flow through your application.
- Declarative Routing: Use attributes like
[Routes]and[Route]to define handlers. - Async Interceptor Pipeline: Build sophisticated message processing chains.
- Versatile Compatibility: Works seamlessly in both Unity and standard .NET projects.
- DI Integration: Native support for VContainer (Unity) and Microsoft.Extensions.DependencyInjection.
Core Concepts
VitalRouter follows a simple messaging flow. A Publisher sends a Command to a Router, which then dispatches it through optional Interceptors to one or more Handlers.
---
config:
theme: dark
---
graph LR
Publisher[Publisher] -- PublishAsync --> Router[Router]
subgraph Pipeline
Router -- next --> Interceptor1[Interceptor A]
Interceptor1 -- next --> Interceptor2[Interceptor B]
end
Interceptor2 -- Invoke --> Handler[Handler/Presenter]
1. Define a Command
Commands are lightweight data structures representing an event or action.
// record structs are recommended for zero-allocation messaging
public readonly record struct MoveCommand(Vector3 Destination) : ICommand;
AOT/HybridCLR Note: While record struct is valid, ensure your AOT metadata is correctly generated for iOS/AOT environments if using tools like HybridCLR.
2. Create a Handler (Presenter)
Use the [Routes] attribute on a partial class to receive commands.
[Routes]
public partial class PlayerPresenter
{
// Use ValueTask for pure .NET performance
[Route]
public void On(MoveCommand cmd)
{
Console.WriteLine($"Moving to {cmd.Destination}");
}
// Use UniTask for Unity-specific async handling
[Route]
public async UniTask On(SomeAsyncCommand cmd)
{
await DoSomethingAsync();
}
}
3. Map and Publish
Connect your handler to a router and start sending commands.
var router = new Router();
var presenter = new PlayerPresenter();
// MapTo returns a Subscription (IDisposable)
using var subscription = presenter.MapTo(router);
// Publish a message
await router.PublishAsync(new MoveCommand(new Vector3(1, 0, 0)));
(Optional) Naive Pub/Sub
You can also subscribe using lambdas without using the source generator.
// Simple subscription
router.Subscribe<MoveCommand>(cmd => { /* ... */ });
// Async subscription with ordering
router.SubscribeAwait<MoveCommand>(async (cmd, ct) =>
{
await DoSomethingAsync();
}, CommandOrdering.Sequential);
// Inline interceptors (Filters)
router
.WithFilter<MoveCommand>(async (cmd, context, next) =>
{
Console.WriteLine("Before");
await next(cmd, context);
Console.WriteLine("After");
})
.Subscribe(cmd => { /* ... */ });
Unity Integration
VitalRouter is highly optimized for Unity, especially when combined with UniTask.
MonoBehaviour Example
When using MapTo in a MonoBehaviour, always bind the subscription to the object's lifecycle.
[Routes]
public partial class CharacterController : MonoBehaviour
{
private void Start()
{
// Bind the subscription to this GameObject's lifecycle
this.MapTo(Router.Default).AddTo(destroyCancellationToken);
}
[Route]
public void On(MoveCommand cmd)
{
transform.position = cmd.Destination;
}
}
Assembly Definition (.asmdef): You must reference VitalRouter in your .asmdef file for the Source Generator to process your [Routes] attributes.
UniTask Integration
UniTask is a fast async/await extension for Unity. VitalRouter actively supports UniTask. Requirements: UniTask >= 2.5.5
If UniTask is installed, the VITALROUTER_UNITASK_INTEGRATION flag is automatically turned on, executing optimized GC-free code paths.
Installation
Requirements
- Unity 2022.2+ (Uses Incremental Source Generator)
- .NET 6.0+
Packages
| Package | Latest version |
|---|---|
VitalRouter |
|
VitalRouter.Extensions.DependencyInjection |
|
VitalRouter.R3 |
|
VitalRouter.MRuby |
Unity Installation
Starting with version 2.0, distribution in Unity has been changed to NuGet.
- Install NuGetForUnity.
- Search and install
VitalRouterpackages in the NuGet window.
Optional (UPM)
If you prefer UPM, you can install the assembly for Unity via Git URL:
https://github.com/hadashiA/VitalRouter.git?path=/src/VitalRouter.Unity/Assets/VitalRouter#2.2.0
Advanced Features
Async Interceptor Pipeline
Pipelining of async interceptors for published messages is possible. This is a general strong pattern for data exchange.
<img src="./website/docs/assets/diagram_interceptors.svg" alt="Interceptor Diagram" width="50%" />
R3 Integration
R3 is the next generation Reactive Extensions implementation in the C# world. VitalRouter supports the ability to work with R3.
MRuby Scripting
Control command publishing via external MRuby scripts. Fiber in mruby and async/await in C# are fully integrated.
Appendix: Best Practices
Based on large-scale production usage (e.g., HybridFrame):
- Prefer record structs: For commands that are pure data,
record structprovides equality comparison and zero-allocation benefits. - Explicit Lifecycles: Always use
.AddTo(destroyCancellationToken)or manualDispose()to avoid memory leaks and ghost event handling. - UniTask for Unity: Use
UniTaskorUniTaskVoidas return types in Unity handlers to leverage optimized pooling. UseValueTaskfor pure .NET projects. - Contextual Metadata: Use
PublishContextfor cross-cutting concerns (logging IDs, cancellation tokens, user permissions) rather than polluting your command structs. - Sequential by Default for UI: Use
CommandOrdering.Sequentialfor UI animations or dialogue sequences to prevent race conditions. - DI Integration: In Unity, VContainer (>= 1.16.6) is highly recommended for managing router lifecycles and handler registration.
License
MIT
Author
@hadashiA
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Memory (>= 4.5.4)
- System.Runtime.CompilerServices.Unsafe (>= 6.0.0)
- System.Threading.Tasks.Extensions (>= 4.5.4)
-
.NETStandard 2.1
- System.Memory (>= 4.5.4)
- System.Runtime.CompilerServices.Unsafe (>= 6.0.0)
- System.Threading.Tasks.Extensions (>= 4.5.4)
-
net6.0
- System.Runtime.CompilerServices.Unsafe (>= 6.0.0)
- System.Threading.Tasks.Extensions (>= 4.5.4)
-
net8.0
- System.Runtime.CompilerServices.Unsafe (>= 6.0.0)
- System.Threading.Tasks.Extensions (>= 4.5.4)
-
net9.0
- System.Runtime.CompilerServices.Unsafe (>= 6.0.0)
- System.Threading.Tasks.Extensions (>= 4.5.4)
NuGet packages (4)
Showing the top 4 NuGet packages that depend on VitalRouter:
| Package | Downloads |
|---|---|
|
VitalRouter.Extensions.DependencyInjection
VitalRouter extensions for Microsoft.Extensions.DependencyInjection. |
|
|
VitalRouter.R3
VitalRouter extensions for R3 reactive extensions |
|
|
VitalRouter.MRuby
VitalRouter extensions for mruby scriptions |
|
|
VitalRouter.Benchmark
The zero-allocation in-memory message passing library. The very thin layer that encourages decrative routings. |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on VitalRouter:
| Repository | Stars |
|---|---|
|
annulusgames/ZeroMessenger
Zero-allocation, extremely fast in-memory messaging library for .NET and Unity.
|
| Version | Downloads | Last Updated |
|---|---|---|
| 2.2.0 | 107 | 2/18/2026 |
| 2.1.0 | 219 | 2/11/2026 |
| 2.0.5 | 259 | 12/31/2025 |
| 2.0.4 | 405 | 12/15/2025 |
| 2.0.3 | 336 | 11/7/2025 |
| 2.0.2 | 307 | 11/3/2025 |
| 2.0.1 | 289 | 10/31/2025 |
| 2.0.0 | 324 | 10/5/2025 |
| 1.7.0 | 257 | 7/15/2025 |
| 1.6.5 | 308 | 5/12/2025 |
| 1.6.2 | 236 | 12/31/2024 |
| 1.6.1 | 253 | 11/23/2024 |
| 1.6.0 | 224 | 11/15/2024 |
| 1.5.0 | 271 | 10/28/2024 |
| 1.4.7 | 213 | 10/21/2024 |
| 1.4.6 | 242 | 10/18/2024 |
| 1.4.5 | 215 | 10/13/2024 |
| 1.4.4 | 233 | 10/11/2024 |
| 1.4.3 | 212 | 10/4/2024 |
| 1.4.2 | 238 | 10/1/2024 |