RabstackQuery 0.3.0

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

RabStack Query

A .NET port of TanStack Query providing declarative query and mutation management with automatic caching, background refetching, and optimistic updates.

Installation

dotnet add package RabstackQuery

For MVVM bindings (MAUI, WPF, Avalonia), also install RabstackQuery.Mvvm. For Blazor, install RabstackQuery.Blazor.

Quick Start

// Create a QueryClient (typically registered as a singleton)
var queryCache = new QueryCache();
var client = new QueryClient(queryCache);

// Fetch data with automatic caching
var result = await client.FetchQueryAsync(new FetchQueryOptions<List<Todo>>
{
    QueryKey = ["todos"],
    QueryFn = async ctx => await api.GetTodosAsync(ctx.CancellationToken)
});

Features

  • Automatic Caching with configurable stale time and garbage collection
  • Stale-While-Revalidate serves cached data instantly while refetching in the background
  • Background Refetching on window focus, network reconnection, and custom intervals
  • Retry with Exponential Backoff (1s, 2s, 4s, 8s, capped at 30s) with configurable attempts
  • Mutations with full lifecycle callbacks (OnMutate, OnSuccess, OnError, OnSettled)
  • Optimistic Updates with automatic rollback on failure
  • Query Invalidation with prefix matching for granular or bulk cache control
  • Reusable Query Definitions via QueryOptions<TData> (analogous to TanStack v5's queryOptions())
  • Observability via System.Diagnostics.Metrics (18 instruments, opt-in via IMeterFactory)
  • Trim and AOT Compatible with zero reflection in library code

Core Concepts

Query Keys

Query keys use C# 12 collection expressions for hierarchical cache identity:

QueryKey key = ["todos"];                          // all todos
QueryKey key = ["todos", todoId];                  // single todo
QueryKey key = ["todos", new { status, page }];    // filtered list

Query Observer

Subscribe to reactive query state updates:

var observer = new QueryObserver<List<Todo>>(client, new QueryObserverOptions<List<Todo>>
{
    QueryKey = ["todos"],
    QueryFn = async ctx => await api.GetTodosAsync(ctx.CancellationToken),
    StaleTime = TimeSpan.FromMinutes(5)
});

observer.Subscribe(result =>
{
    Console.WriteLine($"Status: {result.Status}, Items: {result.Data?.Count}");
});

Select Transforms

Transform cached data without duplicating it:

// Cache stores List<Todo>, observer returns only the count
var observer = new QueryObserver<int, List<Todo>>(client, new QueryObserverOptions<int, List<Todo>>
{
    QueryKey = ["todos"],
    QueryFn = async ctx => await api.GetTodosAsync(ctx.CancellationToken),
    Select = todos => todos.Count
});

Mutations with Optimistic Updates

await client.MutateAsync(new MutationOptions<Todo, Exception, CreateTodoRequest, List<Todo>>
{
    MutationFn = async (request, _, ct) => await api.CreateTodoAsync(request, ct),
    OnMutate = async request =>
    {
        await client.CancelQueriesAsync(["todos"]);
        var previous = client.GetQueryData<List<Todo>>(["todos"]) ?? [];
        client.SetQueryData(["todos"], [.. previous, new Todo { Title = request.Title }]);
        return previous;  // context for rollback
    },
    OnError = (_, _, previous) =>
    {
        if (previous is not null) client.SetQueryData(["todos"], previous);
    },
    OnSettled = (_, _, _, _) => client.InvalidateQueries(["todos"])
},
new CreateTodoRequest { Title = "New todo" });

Cache Operations

// Manual cache reads and writes
client.SetQueryData(["user", userId], updatedUser);
var cached = client.GetQueryData<User>(["user", userId]);

// Invalidate all queries starting with "todos"
client.InvalidateQueries(["todos"]);

// Force refetch specific queries
client.RefetchQueries(["todos", "active"]);

// Remove queries from the cache
client.RemoveQueries(["todos", "deleted-item"]);

Focus and Online Managers

// Notify the library when the app gains/loses focus
FocusManager.Instance.SetFocused(true);

// Notify when network connectivity changes
OnlineManager.Instance.SetOnline(true);

Configuration

// Global defaults
client.SetDefaultOptions(new DefaultOptions
{
    Queries = new QueryConfiguration<object>
    {
        StaleTime = TimeSpan.FromMinutes(1),
        GcTime = TimeSpan.FromMinutes(10),
        Retry = 3,
        NetworkMode = NetworkMode.Online
    }
});

// Per-key defaults
client.SetQueryDefaults(["todos"], new QueryConfiguration<object>
{
    StaleTime = TimeSpan.FromMinutes(5)
});

Documentation

See the GitHub repository for full documentation, architecture guide, and examples.

License

MIT

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (4)

Showing the top 4 NuGet packages that depend on RabstackQuery:

Package Downloads
RabstackQuery.Mvvm

MVVM bindings for RabStack Query — INotifyPropertyChanged ViewModels for Blazor and MAUI with automatic UI thread marshaling.

RabstackQuery.DevTools

Package Description

RabstackQuery.DevTools.Maui

Package Description

RabstackQuery.DevTools.Blazor

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.3.0 125 4/5/2026
0.2.0 121 3/29/2026
0.1.0 139 3/28/2026