.NET SDK

The official Torque .NET SDK provides high-level clients for the HTTP search/management API, TCP binary ingest protocol, and TQBF binary file writing. Zero external NuGet dependencies, targeting .NET 10.

Installation

dotnet add package Torque.Http

HTTP Client

The TorqueHttpClient class is the main entry point for the HTTP API:

using Torque.Http;
using Torque.Http.Search;

var client = new TorqueHttpClient(new TorqueHttpClientOptions
{
    ApiKey = "YOUR_API_KEY",
    BaseUrl = "http://localhost:8108",
});

// Health check
var health = await client.HealthAsync();

// List collections
var collections = await client.Collections.ListAsync();

// Search
var results = await client.SearchAsync("products", new SearchParameters
{
    Q = "running shoes",
    QueryBy = "title,description",
    FilterBy = "in_stock:true",
    SortBy = "price:asc",
    PerPage = 20
});

Multi-Node with Failover

var client = new TorqueHttpClient(new TorqueHttpClientOptions
{
    ApiKey = "YOUR_API_KEY",
    Nodes =
    [
        new Uri("https://node1.example.com:8108"),
        new Uri("https://node2.example.com:8108"),
    ],
    MaxRetries = 3,
    RetryBackoff = TimeSpan.FromMilliseconds(100),
});

Sub-Clients

The TorqueClient exposes specialized sub-clients for each resource type:

PropertyDescription
client.CollectionsCreate, list, get, update, delete collections
client.DocumentsImport, export, create, get, update, delete documents
client.KeysCreate, list, get, delete API keys
client.AliasesCreate, list, get, delete aliases
client.SynonymsManage synonym sets and items
client.PresetsCreate, list, get, delete presets
client.StopwordsCreate, list, get, delete stopword sets

Search

// Simple search
var results = await client.SearchAsync("products", new SearchParameters
{
    Q = "shoes",
    QueryBy = "title"
});

foreach (var hit in results.Hits)
{
    Console.WriteLine($"{hit.Document["title"]} - {hit.Document["price"]}");
}

// Grouped search
var grouped = await client.SearchGroupedAsync("products", new SearchParameters
{
    Q = "shoes",
    QueryBy = "title",
    GroupBy = "brand",
    GroupLimit = 3
});

foreach (var group in grouped.GroupedHits)
{
    Console.WriteLine($"Brand: {string.Join(", ", group.GroupKey)} ({group.Found} hits)");
}

// Multi-search
var multi = await client.MultiSearchAsync(new MultiSearchRequest
{
    Searches =
    [
        new MultiSearchQuery { Collection = "products", Q = "shoes", QueryBy = "title" },
        new MultiSearchQuery { Collection = "articles", Q = "shoes", QueryBy = "body" },
    ],
});

Collection Management

// Create a collection
await client.Collections.CreateAsync(new CollectionSchema
{
    Name = "products",
    Fields = new[]
    {
        new FieldDefinition { Name = "title", Type = "string" },
        new FieldDefinition { Name = "price", Type = "float", Sort = true },
        new FieldDefinition { Name = "category", Type = "string", Facet = true }
    },
    DefaultSortingField = "price"
});

// Update schema (add a field)
await client.Collections.UpdateAsync("products", new CollectionSchemaUpdate
{
    Fields = new[]
    {
        new FieldDefinition { Name = "brand", Type = "string", Facet = true }
    }
});

// Delete a collection
await client.Collections.DeleteAsync("products");

Dependency Injection

Register the client in your ASP.NET Core or Generic Host application using TorqueHttpClientFactory:

using Torque.Http;

builder.Services.AddSingleton<ITorqueHttpClient>(sp =>
    TorqueHttpClientFactory.Create(options =>
    {
        options.ApiKey = "YOUR_API_KEY";
        options.BaseUrl = "http://localhost:8108";
    }));

Or with IHttpClientFactory:

builder.Services.AddHttpClient("Torque");
builder.Services.AddSingleton<ITorqueHttpClient>(sp =>
{
    var factory = sp.GetRequiredService<IHttpClientFactory>();
    var httpClient = factory.CreateClient("Torque");
    return TorqueHttpClientFactory.Create(httpClient, options =>
    {
        options.ApiKey = "YOUR_API_KEY";
    });
});

Then inject ITorqueHttpClient into your services:

public class MyService(ITorqueHttpClient torque)
{
    public async Task SearchAsync()
    {
        var results = await torque.SearchAsync("products", new SearchParameters { Q = "shoes" });
    }
}

TCP Binary Ingestion

The TorqueIngestClient provides high-throughput document streaming via the binary TCP protocol. Host and port are supplied via TorqueIngestOptions; operations run directly on the client (there is no separate session object).

using Torque.Http.Tcp;
using Torque.Http.Models;

// Fetch the collection schema (needed to build and encode documents)
var collection = await client.Collections.GetAsync("products");
var schema = new CollectionSchema
{
    Name = collection.Name,
    Fields = collection.Fields,
};

await using var ingest = new TorqueIngestClient(new TorqueIngestOptions
{
    Host = "localhost",
    Port = 8109,
});
await ingest.ConnectAsync();
await ingest.StartIngestAsync("products");

// Batch mode: stream documents, then commit
var batch = new List<TorqueDocument>(5000);
for (int i = 0; i < 100000; i++)
{
    var doc = new TorqueDocumentBuilder()
        .SetId($"product_{i}")
        .Set("title", $"Product {i}")
        .Set("price", 9.99 + i * 0.01)
        .Set("category", "Electronics")
        .Build(schema);
    batch.Add(doc);

    if (batch.Count == 5000)
    {
        await ingest.SendBatchAsync(batch, schema);
        batch.Clear();
    }
}
if (batch.Count > 0)
    await ingest.SendBatchAsync(batch, schema);

var ack = await ingest.CommitAsync();
Console.WriteLine($"Committed: seq={ack.BatchSeq}, docs={ack.DocsReceived}");

Realtime Mode

For stateless upserts against a realtime collection, use UpsertAsync — no StartIngest/Commit flow needed:

var doc = new TorqueDocumentBuilder()
    .SetId("product_new")
    .Set("title", "New Product")
    .Set("price", 29.99)
    .Build(schema);

await ingest.UpsertAsync("products", doc, schema);
// Document is immediately searchable

Document Builder

The TorqueDocumentBuilder creates documents with typed field values. All field values go through overloaded Set methods that match the wire encoding for the matching schema type.

MethodSchema Type
SetId(string id)Document external ID
SetLanguage(Language lang)Document language
Set(name, string)string
Set(name, int)int32
Set(name, long)int64
Set(name, double)float
Set(name, bool)bool
SetGeoPoint(name, lat, lng)geopoint
Set(name, string[])string[]
Set(name, int[])int32[]
Set(name, long[])int64[]
Set(name, float[])float[] (vector)
SetNull(name)Explicit null field
Build(CollectionSchema)Finalize the document for the given schema

TQBF Binary File Writer

The TorqueBinaryWriter creates TQBF binary files for bulk import via POST /collections/{name}/documents/import-binary. Documents are encoded with ZLib compression, eliminating all parsing overhead at import time:

using Torque.Http.Tcp;
using Torque.Http.Models;

// Build a CollectionSchema that matches the target collection's field layout
var schema = new CollectionSchema
{
    Name = "products",
    Fields =
    [
        new() { Name = "title", Type = "string" },
        new() { Name = "price", Type = "float", Sort = true },
        new() { Name = "category", Type = "string", Facet = true },
    ],
};

await using var writer = new TorqueBinaryWriter(schema, "output.tqbf");
foreach (var doc in documents)
    writer.Write(doc);
await writer.FinalizeAsync();

// The writer uploads itself via HTTP POST /collections/{name}/documents/import-binary
using var httpClient = new HttpClient { BaseAddress = new Uri("http://localhost:8108") };
var result = await writer.UploadAsync(httpClient, "products", "YOUR_API_KEY");
Console.WriteLine($"Imported {result.NumImported} documents");

Import & Export Options

// Import with upsert action and options
var results = await client.Documents.ImportAsync("products", jsonlLines,
    ImportAction.Upsert, new ImportOptions { BatchSize = 100 });

// Export with field filtering (streaming)
await foreach (var doc in client.Documents.ExportStreamingAsync("products",
    includeFields: "id,title,price"))
{
    Console.WriteLine(doc);
}

Models

The SDK includes typed models for all API responses:

  • SearchResult, GroupedSearchResult, Hit — search responses
  • CollectionSchema, FieldDefinition — collection schemas
  • ApiKey, Alias, Synonym, Preset, Stopword — management resources
  • ImportResult, IngestResult — ingestion results
  • AdminStats, Health — server status

All serialization uses System.Text.Json with source-generated serialization contexts for optimal performance.

Error Handling

HTTP API errors throw TorqueApiException with the HTTP status code and error message. TCP protocol errors are returned as IngestError with an error code and description.