RevalQuery.Blazor 0.3.0

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

RevalQuery

Data fetching library for Blazor. Built on RevalQuery.Core.

Inspired by TanStack Query, RevalQuery provides type-safe async data fetching, caching, and state management for Blazor WebAssembly and Blazor Server.

Quick Start

@using CachingDemo.Client.Services
@using RevalQuery.Core
@rendermode InteractiveWebAssembly
@inherits RevalQuery.Blazor.QueryComponentBase

<PageTitle>Search Bar Example</PageTitle>

<div class="search-box">
    <div style="display: flex; gap: 8px;">
        <input @bind="SearchTerm" @bind:event="oninput" placeholder="Type to search..."/>

        @if (Suggestions.IsFetching)
        {
            <div>
                Loading...
            </div>
        }
    </div>

    @if (Suggestions.Error is not null)
    {
        <p style="color:red">Error: @Suggestions.Error.Message</p>
    }
    else if (Suggestions.Data is not null)
    {
        <ul>
            @foreach (var item in Suggestions.Data)
            {
                <li>@item</li>
            }
        </ul>
    }
    else if (!Suggestions.IsFetching)
    {
        <p><em>Nothing to show</em></p>
    }
</div>

@code {
    private string SearchTerm { get; set; } = string.Empty;

    IQueryState<List<string>> Suggestions => UseQuery(
        key: ("search", SearchTerm),
        handler: async static ctx =>
        {
            var res = await SearchService.SearchAsync(ctx.Key.SearchTerm);
            return QueryResult.Success(res);
        },
        options => options
            .ConfigureFetch(fetch => fetch
                .StaleTime(TimeSpan.FromMinutes(5))
            )
    );
}

Table of Contents


Installation

Register in both client and server Program.cs:

// Server/Program.cs
builder.Services.AddRevalQuery();

// Client/Program.cs  
builder.Services.AddRevalQuery();

Required for Blazor WebAssembly prerendering support.


Component Integration

Inherit from QueryComponentBase:

@inherit QueryComponentBase

UseQuery

Subscribe to a query - observes data and manages lifecycle automatically.

IQueryState<User[]> Users => UseQuery(
    key: ("users",),
    handler: async static ctx =>
        await ctx.ServiceProvider.GetRequiredService<IUserService>().GetAll()
);

Static handlers: Handlers must be static. Using static ensures compilation error if the handler accidentally captures component state. This guarantees pure, stateless functions that won't cause memory leaks or stale closures.

// Correct - static handler
handler: async static ctx => ...

// Compilation error with static - captures state
handler: async static ctx => someComponentField  // Compile error

UseMutation

Execute write operations (Create/Update/Delete). Supports callbacks.

MutationState<CreateUserRequest, User> CreateUserMutation => UseMutation(
    MutationOptions.Create<CreateUserRequest, User>(
        async static ctx =>
            await ctx.ServiceProvider.GetRequiredService<IUserService>().CreateAsync(ctx.Params)
    )
    .OnResolved(async (user, _) => Console.WriteLine($"Created {user.Name}"))
    .OnException(async (ex, _) => Console.WriteLine($"Error: {ex.Message}"))
);

// Trigger mutation
await CreateUserMutation.ExecuteAsync(new CreateUserRequest { Name = "John" });

QueryFactory Pattern

For reusability across components, define queries in static classes. This keeps query definitions centralized, makes keys consistent, and simplifies invalidation.

public static class UserQueries
{
    private const string Token = "users";

    // For invalidation - centralized key definition
    public static (string, int) GetKey(int userId) => (Token, userId);

    // Returns builder - components can extend configuration
    public static QueryOptionsBuilder<(string, int), User> GetUserOptions(int userId)
    {
        return QueryOptions.Create(
            key: (Token, userId),
            handler: async static ctx =>
                await ctx.ServiceProvider.GetRequiredService<IUserService>().GetByIdAsync(ctx.Key.Item2)
        );
    }
}

Usage in component:

IQueryState<User> User => UseQuery(
    UserQueries.GetUserOptions(userId)
        .ConfigureFetch(f => f.StaleTime(TimeSpan.FromMinutes(5)))
        .ConfigureRetry(r => r.Retry(3))
);

For invalidation:

Client.Invalidate(UserQueries.GetKey(userId));

Benefits:

  • Single source of truth for query definitions
  • Consistent key format across the app
  • Easy bulk invalidation
  • Components extend factory options via builder pattern

QueryState Properties

Access query state via IQueryState<T>:

Property Description
Data The fetched data (null if pending/error)
Exception The error if query failed
IsPending No data yet
IsResolved Data available
IsException Query failed
IsFetching Currently fetching
IsLoading Fetching + no data (IsFetching && IsPending)
IsIdle Not fetching
LastUpdatedAt Timestamp of last successful fetch

Configuration

Query lifecycle callbacks (onSuccess, onError, onSettled) are NOT supported on queries. Use IQueryState properties directly in components:

@if (Users.IsResolved)
{
    <p>Loaded @Users.Data?.Length users</p>
}
@else if (Users.IsFetching)
{
    <p>Loading...</p>
}
@else if (Users.IsException)
{
    <p>Error: @Users.Exception.Message</p>
}

License

MIT

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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 is compatible.  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 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

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.3.0 89 5/7/2026
0.2.0 100 4/8/2026
0.1.3 99 3/25/2026
0.1.2 97 3/24/2026
0.1.1 97 3/24/2026