AssuanLibrary 1.0.2

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

Assuan Library (.NET)

AssuanLibrary is a modern, transport-agnostic .NET implementation of the Assuan protocol, designed to build clients and servers that speak Assuan over multiple transports such as TCP, Named Pipes (Windows), Unix Domain Sockets (Linux), and any other custom transport you implement.

The library focuses on:

  • correctness of the Assuan protocol lifecycle
  • clean separation between protocol, transport, and application logic
  • explicit, hook-based session control
  • minimal assumptions about authentication and policy

Features

  • Assuan protocol encoder/decoder
  • Client and server implementations
  • Multi-transport support:
    • TCP
    • Named Pipes (Windows)
    • Unix Domain Sockets (Linux)
  • Custom command handlers
  • INQUIRE support (sync and async)
  • Explicit session lifecycle hooks
  • No implicit protocol behavior
  • Suitable for embedding or standalone servers

Design Principles

AssuanLibrary follows a few strict principles:

  • Transport is not protocol
    • Connections know how to read/write bytes, not how to speak Assuan.
  • Protocol is explicit
    • Nothing is sent automatically unless explicitly configured.
  • Lifecycle is deterministic
    • Authentication, banner handling, command dispatch, and shutdown all have a defined order.
  • Hooks over magic
    • Custom behavior is implemented via explicit hooks, not hidden logic.

Supported Transports

Transport Platform
TCP Cross-platform
Named Pipes Windows
Unix Domain Sockets Linux / macOS¹

Transport selection is done via endpoints if not provided, not by hardcoding logic into the client or server.

PS¹: Unix Domain Sockets are supported on Linux. macOS has not been tested but should work similarly.

Installation

dotnet add package AssuanLibrary

Optional dependency injection helpers (recommended but not required):

dotnet add package AssuanLibrary.Extensions.DependencyInjection

Usage

GnuPG agent client example:

// ----- REQUIRED ONLY FOR TCP CLIENT ON WINDOWS THAT USES GNUPG AGENT -----
var options = new AssuanClientOptions
{
  OnSessionAuthenticatingAsync = async (connection, ctx, ct) =>
  {
    if (ctx.TryGetValue("nonce", out var nonceObj) && nonceObj is byte[] nonce)
    {
      await connection.WriteAsync(nonce, ct); // Flushes automatically after writing
    }
  }
};
// ---------------------------------------------------

await using var client = new AssuanClient(options);
await client.ConnectAsync(AssuanEndpointKind.AGENT, ct); // Resolves automatically into the correct transport if not provided on AssuanClient

var command = new AssuanCommand("GETINFO") { "version" };
var responseCollection = await client.InvokeAsync(command, ct);

foreach (var response in responseCollection)
{
    Console.WriteLine(response);
}

// ------------------ IF YOU ALREADY KNOWS THE ENDPOINT AND THE NONCE ON WINDOWS ------------------
var tcpEndpoint = new TcpClientEndpoint(IPAddress.Loopback, 12345);
var metadata = new Dictionary<string, object>
{
  ["nonce"] = System.Text.Encoding.UTF8.GetBytes("my-secret-nonce") // Replace with the actual nonce value
};
await using var client = new AssuanClient();
await client.ConnectAsync(tcpEndpoint, metadata, ct);

var command = new AssuanCommand("GETINFO") { "version" };
var responseCollection = await client.InvokeAsync(command, ct);

foreach (var response in responseCollection)
{
    Console.WriteLine(response);
}
// -------------------------------------------------------------------------------------

// Expected output:
// D 2.2.27
// OK

Custom-Server client example:

var options = new AssuanClientOptions // Those options are not required, we are just adding them for demonstration
{
  OnSessionStartedAsync = async (connection, ctx, ct) =>
  {
    if (ctx.TryGetValue("banner", out var bannerObj) && bannerObj is byte[] banner)
    {
      Console.WriteLine($"Server Banner: {System.Text.Encoding.UTF8.GetString(banner)}");
    }
  }
};

var serverEndpoint = new TcpClientEndpoint(IPAddress.Loopback, 23456);
await using var client = new AssuanClient(options);
await client.ConnectAsync(serverEndpoint, new Dictionary<string, object>(), ct);

var command = new AssuanCommand("SOME_COMMAND") { "some_argument" };
var responseCollection = await client.InvokeAsync(command, ct);

foreach (var response in responseCollection)
{
    Console.WriteLine(response);
}

Custom Server example:

public sealed class GetInfoCommandHandler : CommandHandler
{
  /// <inheritdoc />
  public override string Name => "GETINFO";

  /// <inheritdoc />
  public override async Task HandleAsync(IReadOnlyAssuanCommand command, IServerContext serverContext) {
    foreach (var arg in command.Arguments) {
      switch (arg) {
        case "version": {
          var responseCollection = AssuanResponseCollection.Create(
            AssuanResponse.Data(typeof(GetInfoCommandHandler).Assembly.GetName().Version?.ToString() ?? "unknown"),
            AssuanResponse.Ok()
          );
          await serverContext.SendResponseAsync(responseCollection, serverContext.Session.CancellationToken);
          break;
        }
        case "pid": {
          var responseCollection = AssuanResponseCollection.Create(
            AssuanResponse.Data(Environment.ProcessId.ToString()),
            AssuanResponse.Ok()
          );
          await serverContext.SendResponseAsync(responseCollection, serverContext.Session.CancellationToken);
          break;
        }
        default:
          await serverContext.SendResponseAsync(AssuanResponse.Error(45, "Invalid argument"),
            serverContext.Session.CancellationToken);
          break;
      }
    }
  }
}

var serverOptions = new AssuanServerOptions
{
  Banner = "My Custom Assuan Server"
};

var server = new AssuanServer(serverOptions);
server.RegisterCommandHandler(new GetInfoCommandHandler());
// server.RegisterCommandHandler<GetInfoCommandHandler>();
var tcpEndpoint = new TcpServerEndpoint(IPAddress.Loopback, 23456);
await server.RunAsync(tcpEndpoint, ct);

Contributing

Contributions are welcome! Please refer to the CONTRIBUTING guide for more information.

License

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

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  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 was computed.  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. 
.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 was computed. 
.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. 
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 AssuanLibrary:

Package Downloads
AssuanLibrary.Extensions.DependencyInjection

A .NET library for interacting with the Assuan protocol.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.2 117 1/31/2026
1.0.0 221 1/30/2026