Skip to main content
net8.0net10.0

C# SDK for the HnswLite REST API — approximate nearest neighbor search powered by HNSW graphs.

Published
Apr 17, 2026
6mo ago
Total Downloads
875
875

Install

dotnet add package HnswLite.Sdk --version 1.1.2
ProductVersions
.NET
net10.0net8.0

README

HnswLite C# SDK

C# SDK for the HnswLite REST API. Provides full async coverage of every endpoint for index management, vector operations, and K-nearest-neighbour search.

Installation

dotnet add package HnswLite.Sdk

Or via the NuGet Package Manager:

Install-Package HnswLite.Sdk

Quick Start

using HnswLite.Sdk;
using HnswLite.Sdk.Models;

using HnswLiteClient client = new HnswLiteClient(
    baseUrl: "http://localhost:8080",
    apiKey: "your-api-key"
);

Usage Examples

Health Check (Ping)

// GET / — unauthenticated health ping
bool isAlive = await client.PingAsync();
Console.WriteLine("Server alive: " + isAlive);

// HEAD / — unauthenticated head ping
bool headOk = await client.HeadPingAsync();

Create an Index

IndexResponse index = await client.CreateIndexAsync(new CreateIndexRequest
{
    Name = "my-index",
    Dimension = 384,
    StorageType = "RAM",           // "RAM" or "SQLite"
    DistanceFunction = "Cosine",   // "Euclidean", "Cosine", or "DotProduct"
    M = 16,
    MaxM = 32,
    EfConstruction = 200
});

Console.WriteLine("Created index: " + index.Name + " (GUID: " + index.GUID + ")");

Get an Index

IndexResponse index = await client.GetIndexAsync("my-index");
Console.WriteLine("Vectors: " + index.VectorCount);

Enumerate Indexes

EnumerationResult<IndexResponse> page = await client.EnumerateIndexesAsync(new EnumerationQuery
{
    MaxResults = 25,
    Skip = 0,
    Ordering = EnumerationOrderEnum.NameAscending,
    Prefix = "prod-"
});

foreach (IndexResponse idx in page.Objects)
{
    Console.WriteLine(idx.Name + " (" + idx.VectorCount + " vectors)");
}

Console.WriteLine("End of results: " + page.EndOfResults);
Console.WriteLine("Total records: " + page.TotalRecords);

Add a Single Vector

AddVectorRequest echo = await client.AddVectorAsync("my-index", new AddVectorRequest
{
    Vector = new List<float> { 0.1f, 0.2f, 0.3f /* ... */ }
});

Console.WriteLine("Added vector GUID: " + echo.GUID);

Add a Batch of Vectors

AddVectorsRequest batchEcho = await client.AddVectorsAsync("my-index", new AddVectorsRequest
{
    Vectors = new List<AddVectorRequest>
    {
        new AddVectorRequest { Vector = new List<float> { 0.1f, 0.2f, 0.3f } },
        new AddVectorRequest { Vector = new List<float> { 0.4f, 0.5f, 0.6f } },
        new AddVectorRequest { Vector = new List<float> { 0.7f, 0.8f, 0.9f } }
    }
});

Console.WriteLine("Added " + batchEcho.Vectors.Count + " vectors");

Search (K-Nearest Neighbours)

SearchResponse result = await client.SearchAsync("my-index", new SearchRequest
{
    Vector = new List<float> { 0.1f, 0.2f, 0.3f /* ... */ },
    K = 10,
    Ef = 200  // optional; null uses server default
});

Console.WriteLine("Search took " + result.SearchTimeMs + " ms");

foreach (VectorSearchResult r in result.Results)
{
    Console.WriteLine("  GUID: " + r.GUID + " Distance: " + r.Distance);
}

Enumerate Vectors

// GUIDs only (includeVectors defaults to false)
EnumerationResult<VectorEntryResponse> page = await client.EnumerateVectorsAsync(
    "my-index",
    new EnumerationQuery { MaxResults = 50 });

Console.WriteLine("Total vectors: " + page.TotalRecords);
foreach (VectorEntryResponse v in page.Objects)
{
    Console.WriteLine("  GUID: " + v.GUID);
}

// Include the full vector values
EnumerationResult<VectorEntryResponse> detailed = await client.EnumerateVectorsAsync(
    "my-index",
    new EnumerationQuery { MaxResults = 10 },
    includeVectors: true);

foreach (VectorEntryResponse v in detailed.Objects)
{
    Console.WriteLine("  GUID: " + v.GUID + " Dim: " + v.Vector.Count);
}

Get a Single Vector

Guid vectorId = Guid.Parse("...");
VectorEntryResponse entry = await client.GetVectorAsync("my-index", vectorId);

Console.WriteLine("GUID: " + entry.GUID);
Console.WriteLine("Vector: [" + string.Join(", ", entry.Vector) + "]");

Remove a Vector

Guid vectorId = Guid.Parse("...");
await client.RemoveVectorAsync("my-index", vectorId);

Delete an Index

await client.DeleteIndexAsync("my-index");

Error Handling

All non-2xx responses throw HnswLiteApiException:

try
{
    IndexResponse index = await client.GetIndexAsync("nonexistent");
}
catch (HnswLiteApiException ex)
{
    Console.WriteLine("Status: " + (int)ex.StatusCode);  // e.g. 404
    Console.WriteLine("Error:  " + ex.Error);             // e.g. "IndexNotFound"
    Console.WriteLine("Detail: " + ex.ApiMessage);        // Human-readable message
}

Cancellation

Every async method accepts an optional CancellationToken:

using CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
IndexResponse index = await client.GetIndexAsync("my-index", cts.Token);

Custom API Key Header

The API key header name is configurable (defaults to x-api-key):

using HnswLiteClient client = new HnswLiteClient(
    baseUrl: "http://localhost:8080",
    apiKey: "your-api-key",
    apiKeyHeader: "Authorization"
);

Running the Test Harness

cd sdk/csharp/HnswLite.Sdk.Test
dotnet run -- http://localhost:8080 your-api-key

The test harness exercises every SDK method and prints pass/fail for each. Exit code 0 means all tests passed.

Target Frameworks

  • .NET 8.0
  • .NET 10.0

Changes from Previous Version

No structural changes between v1.1.1 and v1.1.2.

Adoption Assessment

Assess this package against its supported frameworks, license, maintenance signals and dependency graph before making it a project standard.

No SPDX license expression is published. Review the license text and your organisation's policy before redistribution.Compatibility metadata lists 2 target frameworks; confirm the exact target used by your application.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.