C# bindings for Eclipse Zenoh distributed messaging — embedded native runtime and Unity support.
Unofficial, community-maintained bindings. This project is not affiliated with or endorsed by the Eclipse Foundation. "Zenoh" is a trademark of the Eclipse Foundation.
| Maturity | Alpha — APIs may change; package versions track the embedded Zenoh runtime |
| Package version | 1.9.0.x = Zenoh 1.9.0 + dotnet release patch (see Versioning) |
| Zenoh runtime | zenoh Rust 1.9.0, statically linked into native binaries |
| Production use | Evaluate for your workload; no stability guarantees yet |
Available today: Session, Publisher, Subscriber, Query/Queryable, Liveliness, Source Generator; .NET 8+ and Unity 2021.3+ on desktop platforms.
Caveats: Performance is not fully tuned; test coverage is still growing; Android/iOS libraries require a manual cross-build. Migrating from Zenoh 1.8.x peers/routers may need config updates.
Terms: LICENSE (MIT for this repo) · THIRD_PARTY_NOTICES.md (Apache-2.0 for bundled Zenoh runtime)
ZenohDotNet provides three complementary packages for using Zenoh in .NET and Unity applications:
- ZenohDotNet.Native - Low-level FFI bindings (.NET Standard 2.1) with embedded Zenoh runtime
- ZenohDotNet.Client - High-level async API for .NET 8.0+ with modern C# features
- ZenohDotNet.Unity - Unity-optimized wrapper with UniTask integration
- Embedded Runtime: Zenoh native library (Rust) included — no separate installation required
- Cross-Platform: Windows, Linux, macOS on x64 and ARM64
- Mobile Support: Android (arm64-v8a, armeabi-v7a, x86_64) and iOS (arm64)
- Unity Support: First-class Unity integration with UniTask
- Modern C#: Leverages .NET 8.0 features (async/await, records, pattern matching)
- Type Safe: Strongly-typed APIs with compile-time safety
- Memory Safe: Proper resource management with IDisposable/IAsyncDisposable
┌─────────────────┐
│ Eclipse Zenoh │ ← zenoh Rust crate (Apache-2.0, statically linked)
│ (Rust) │
└────────┬────────┘
│
┌────────▼────────┐
│ Rust FFI │ ← csbindgen generates C# code
│ (zenoh-ffi) │ Dynamic libraries (.dll/.so/.dylib)
└────────┬────────┘
│
┌────────▼────────┐
│ ZenohDotNet.Native │ ← Layer 1: Low-level FFI bindings
│ (.NET Std 2.1) │ NuGet package with embedded runtime
│ [NuGet] │
└────────┬────────┘
│
┌────┴──────┐
│ │
┌───▼──────┐ ┌──▼─────────┐
│ Unity │ │ Client │
│ Wrapper │ │ (.NET 8.0) │
│ (.NETStd │ │ [NuGet] │
│ 2.1) │ └────────────┘
│ [UPM] │
└──────────┘
dotnet add package ZenohDotNet.Clientusing ZenohDotNet.Client;
// Open session
await using var session = await Session.OpenAsync();
// Publisher
await using var publisher = await session.DeclarePublisherAsync("demo/example/test");
await publisher.PutAsync("Hello, Zenoh!");
// Subscriber
await using var subscriber = await session.DeclareSubscriberAsync("demo/example/**", sample =>
{
Console.WriteLine($"Received: {sample.GetPayloadAsString()}");
});
await Task.Delay(-1);- Add
com.zenohdotnet.unityvia UPM (Git URL):https://github.com/konnta0/ZenohDotNet.git#upm
using UnityEngine;
using ZenohDotNet.Unity;
using Cysharp.Threading.Tasks;
public class ZenohExample : MonoBehaviour
{
private Session session;
private Publisher publisher;
async void Start()
{
session = await Session.OpenAsync(this.GetCancellationTokenOnDestroy());
publisher = await session.DeclarePublisherAsync("unity/example/data");
Debug.Log("Zenoh initialized");
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
publisher.Put($"Hello from Unity at {Time.time}");
}
}
void OnDestroy()
{
publisher?.Dispose();
session?.Dispose();
}
}| Platform | Architecture | Status |
|---|---|---|
| Windows | x64 | ✅ Supported |
| Windows | ARM64 | ✅ Supported |
| Linux | x64 | ✅ Supported |
| Linux | ARM64 | ✅ Supported |
| macOS | x64 (Intel) | ✅ Supported |
| macOS | ARM64 (Apple Silicon) | ✅ Supported |
| Platform | Status |
|---|---|
| Windows / Linux / macOS (x64, ARM64) | Supported |
| Android (arm64-v8a, armeabi-v7a, x86_64) | Supported via cross-build |
| iOS (arm64) | Supported via cross-build |
- Rust (latest stable)
- .NET SDK 8.0+
- C/C++ linker toolchain (provided by the Rust toolchain on most platforms)
-
Clone the repository:
git clone https://github.com/konnta0/ZenohDotNet.git cd ZenohDotNet -
Build Rust FFI for your platform:
# Unix/Linux/macOS ./scripts/build-native.sh # Windows .\scripts\build-native.ps1
-
Copy generated bindings:
# Unix/Linux/macOS ./scripts/copy-bindings.sh # Windows .\scripts\copy-bindings.ps1
-
Build C# projects:
dotnet build ZenohDotNet.slnx -c Release
-
Create NuGet packages:
# Unix/Linux/macOS ./scripts/pack-nuget.sh # Windows - Similar script available
-
Create UPM package (for Unity):
./scripts/pack-upm.sh
For building all platforms from a single machine, install cross:
cargo install crossThe build scripts will automatically use cross if available to build for all target platforms.
ZenohDotNet/
├── native/ # Rust FFI layer
│ ├── zenoh-ffi/ # Rust project with csbindgen (links zenoh crate)
│ │ ├── src/lib.rs # FFI function definitions
│ │ └── build.rs # Build script + csbindgen config
│ └── output/ # Build artifacts (gitignored)
│ ├── generated/ # Generated C# code
│ └── {rid}/ # Native libraries per platform
│
├── src/ # C# projects
│ ├── ZenohDotNet.Native/ # Low-level bindings (.NET Standard 2.1)
│ ├── ZenohDotNet.Client/ # High-level API (.NET 8.0)
│ └── ZenohDotNet.Unity/ # Unity project (package development)
│ └── Assets/Plugins/com.zenohdotnet.unity/ # UPM package
│
├── tests/ # Test projects
├── samples/ # Example code
│ ├── dotnet/ # .NET console samples
│ └── unity/ # Unity sample projects
│ └── ZenohUnityExample/ # Unity sample project
├── scripts/ # Build automation
├── packages/ # Build output (gitignored)
│
└── ZenohDotNet.slnx # Solution file (.NET projects only)
Low-level P/Invoke bindings to the embedded Zenoh runtime. Native libraries for all supported platforms are included in the package.
- Target: .NET Standard 2.1
- Use case: Low-level access, Unity compatibility
- API style: Synchronous with IDisposable
Modern async C# API built on ZenohDotNet.Native.
- Target: .NET 8.0+
- Use case: Modern .NET applications
- API style: Async/await with IAsyncDisposable
- Features: JSON support, record types, pattern matching
Unity-optimized wrapper with UniTask integration.
- Package:
com.zenohdotnet.unity(UPM) - Target: .NET Standard 2.1
- Use case: Unity 2021.2+ projects
- API style: UniTask async + synchronous methods
- Features: Main thread callbacks, Unity lifecycle integration
- Dependencies: com.cysharp.unitask (UPM)
Installation via Git URL:
https://github.com/konnta0/ZenohDotNet.git#upm
if you want to use a specific release, append the tag:
https://github.com/konnta0/ZenohDotNet.git#upm@v1.9.0.0
| Feature | ZenohForCSharp | zenoh-csharp |
|---|---|---|
| Embedded Runtime | ✅ Yes | ❌ No (requires external build) |
| Monorepo | ✅ Yes | ❌ No |
| Unity Support | ✅ First-class (UniTask, UPM) | |
| .NET 8.0 Support | ✅ Yes (ZenohDotNet.Client) | ❌ No |
| Cross-platform NuGet | ✅ All platforms in one package | |
| Build Automation | ✅ Full CI/CD |
- Mobile Build Guide - Building for Android and iOS
- ZenohDotNet.Native README - Low-level FFI bindings documentation
- ZenohDotNet.Client README - High-level async API documentation
See the samples directory for complete examples:
- dotnet/Publisher - Basic publisher example
- dotnet/Subscriber - Basic subscriber example
- dotnet/LivelinessToken - Liveliness token example (declare alive resource)
- dotnet/LivelinessSubscriber - Liveliness subscriber example (monitor resource presence)
- unity/ZenohUnityExample - Unity project example
Contributions are welcome! Please feel free to submit a Pull Request.
- Make changes to code
- Build Rust FFI if needed:
./scripts/build-native.sh - Copy bindings:
./scripts/copy-bindings.sh - Build C#:
dotnet build - Run tests:
dotnet test
NuGet and UPM package versions follow {zenoh}.{dotnet-patch} (four numeric segments):
| Version | Meaning |
|---|---|
1.9.0.0 |
Zenoh runtime 1.9.0, first ZenohDotNet release for that runtime |
1.9.0.1 |
Same Zenoh 1.9.0, dotnet-only fix (C# / packaging / docs) |
1.9.1.0 |
Zenoh runtime bumped to 1.9.1 |
Single source of truth: build/Versions.props (ZenohVersion + Version).
# Bump Zenoh runtime to 1.9.1 (resets dotnet patch to 0)
./scripts/bump-version.sh --zenoh 1.9.1 --patch 0
# Dotnet-only patch on current runtime (1.9.0.0 -> 1.9.0.1)
./scripts/bump-version.sh --patch 1
# Verify Cargo.toml, package.json, and notices match Versions.props
./scripts/verify-versions.shRelease: commit the bump, then push one tag — CI publishes all packages with that version:
git tag v1.9.0.0
git push origin v1.9.0.0NuGet may normalize 1.9.0.0 to 1.9.0 in the feed; patch releases (1.9.0.1, …) keep the fourth segment.
Core pub/sub, query, liveliness, Source Generator, cross-platform NuGet/UPM packaging, Unity (UniTask), mobile cross-build support, CI, samples, and benchmarks. Zenoh 1.9.0 runtime with aligned package versioning.
- Zenoh 1.9.x migration notes and config examples in docs
- Advanced Unity features (ScriptableObjects, etc.)
- Broader integration test matrix (router/client topologies)
ZenohDotNet includes an incremental source generator that provides zero-copy serialization for your message types.
<PackageReference Include="ZenohDotNet.Abstractions" Version="1.9.0.0" />
<PackageReference Include="ZenohDotNet.Generator" Version="1.9.0.0" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />Define your message type with the [ZenohMessage] attribute:
using ZenohDotNet.Abstractions;
[ZenohMessage("sensor/temperature")] // Optional default key
public partial struct SensorData
{
public double Temperature { get; init; }
public double Humidity { get; init; }
public DateTime Timestamp { get; init; }
}The generator creates:
ToBytes()- Instance serializationSerialize(in T)- Static zero-copy serializationSerializeTo(in T, Span<byte>)- Stack-allocated serializationDeserialize(byte[])/Deserialize(ReadOnlySpan<byte>)TryDeserialize(ReadOnlySpan<byte>, out T)DefaultKeyExpression- Static property (if default key specified)BuildKeyExpression()- Dynamic key construction (if key parameters specified)SubscriptionPattern- Wildcard pattern for subscribing
Use [ZenohKeyParameter] for keys that include user IDs or other runtime values:
[ZenohMessage("game/player/{PlayerId}/position")]
[ZenohSubscriptionPattern("game/player/*/position")] // Wildcard for subscribing
public partial struct PlayerPosition
{
[ZenohKeyParameter]
public string PlayerId { get; init; }
public float X { get; init; }
public float Y { get; init; }
}
// Usage
var position = new PlayerPosition { PlayerId = "user123", X = 10, Y = 20 };
// Instance method - builds key from properties
var key = position.BuildKeyExpression(); // "game/player/user123/position"
// Static method - pass parameters directly
var key2 = PlayerPosition.BuildKeyExpression("user456");
// Subscribe to all players
subscriber.Subscribe(PlayerPosition.SubscriptionPattern); // "game/player/*/position"var data = new SensorData { Temperature = 25.5, Humidity = 60.0, Timestamp = DateTime.UtcNow };
// Heap allocation (simple)
var bytes = data.ToBytes();
// Zero-copy with stackalloc (high-performance)
Span<byte> buffer = stackalloc byte[256];
var written = SensorData.SerializeTo(in data, buffer);
publisher.Put(buffer.Slice(0, written));struct(recommended for performance - usesinparameter)classrecord/record struct
[ZenohMessage(Encoding = ZenohEncoding.Json)] // Default
[ZenohMessage(Encoding = ZenohEncoding.MessagePack)] // Requires MessagePack package
[ZenohMessage(Encoding = ZenohEncoding.Custom)] // Custom IZenohSerializer<T>The com.zenohdotnet.unity UPM package includes native bindings, native libraries, and Unity wrappers in a single package. No additional NuGet package installation is required.
Note: The NuGet package
ZenohDotNet.Nativeis still published separately for .NET (non-Unity) applications.
Package structure (com.zenohdotnet.unity):
com.zenohdotnet.unity/
├── Runtime/
│ ├── Native/ ← C# FFI bindings (copied by CI)
│ │ ├── NativeMethods.g.cs
│ │ └── ...
│ ├── Session.cs ← Unity wrappers
│ ├── Publisher.cs
│ ├── Subscriber.cs
│ └── ZenohDotNet.Unity.asmdef
├── Editor/
│ └── ZenohUnityEditor.cs
├── Plugins/ ← Native binaries (copied by CI)
│ ├── Windows/x86_64/zenoh_ffi.dll
│ ├── Linux/x86_64/zenoh_ffi.so
│ ├── macOS/zenoh_ffi.dylib
│ └── iOS/zenoh_ffi.a
├── package.json
└── LICENSE.md
Usage in Unity:
using ZenohDotNet.Abstractions;
[ZenohMessage("game/player/position")]
public partial struct PlayerPosition
{
public float X;
public float Y;
public float Z;
}Performance benchmarks are available in the benchmarks/ directory.
# Run all benchmarks
dotnet run -c Release --project benchmarks/ZenohDotNet.Benchmarks
# Run specific benchmark class
dotnet run -c Release --project benchmarks/ZenohDotNet.Benchmarks -- --filter "*SessionBenchmarks*"
# Run quick benchmarks (shorter runs)
dotnet run -c Release --project benchmarks/ZenohDotNet.Benchmarks -- --filter "*" --job Short- SessionBenchmarks - Session open/close, resource declaration
- PubSubBenchmarks - Publisher/Subscriber throughput with various payload sizes
- QueryBenchmarks - Query/Reply latency (single and concurrent)
- ThroughputBenchmarks - Maximum messages per second
- LatencyBenchmarks - End-to-end message latency
- AllocationBenchmarks - Memory allocation patterns
- SessionConfigBenchmarks - Configuration serialization
For lowest latency, use synchronous Put() methods on a dedicated thread:
// Zero-copy publishing with ReadOnlySpan
publisher.Put(myData.AsSpan());
// Synchronous string publishing
publisher.Put("Hello");Use ReadOnlyMemory<byte> or ReadOnlySpan<byte> to avoid copying:
// Async with ReadOnlyMemory (avoids array copy)
await publisher.PutAsync(buffer.AsMemory());
// Sync with ReadOnlySpan (zero-copy)
publisher.Put(buffer.AsSpan());This project is licensed under the MIT License — see the LICENSE file for details.
Native binaries bundled in NuGet and Unity packages include the Eclipse Zenoh runtime, redistributed under the Apache License 2.0. See THIRD_PARTY_NOTICES.md and licenses/.
- Eclipse Zenoh - The underlying distributed messaging system
- csbindgen - Rust FFI to C# binding generator
- UniTask - Unity async/await support
- Zenoh Website
- Zenoh GitHub (Rust)
- NuGet.org
- Unity Asset Store - Coming soon
- GitHub Issues: Report bugs or request features
- Discussions: Ask questions and share ideas
Made with ❤️ for the .NET and Unity communities