Dynamic filtering, sorting, paging, and projection for IQueryable in .NET.
FlexQuery.NET is a dynamic query engine for .NET REST APIs. It turns query-string parameters into secure, server-side expression trees — filtering, sorting, paging, and projecting your data with a single call, without ever evaluating LINQ in memory.
- One endpoint, every query — clients send
filter,sort,page,pageSize,select, and more; your action method stays one line. - 100% server-side — every operation translates to SQL via expression trees. No client evaluation, no surprise full-table loads.
- Security first — whitelists, blacklists, and per-operation field policies are validated before a query ever reaches the database.
- Multiple query syntaxes — the native DSL, FQL (a SQL-inspired language), and a lightweight OData-compatible syntax.
- Provider choice — runs on Entity Framework Core, Dapper (with multi-dialect SQL generation), or any
IQueryablesource.
Install the core package plus a provider:
dotnet add package FlexQuery.NET
dotnet add package FlexQuery.NET.EntityFrameworkCoreConfigure once at startup, then bind FlexQueryParameters in a controller and pass it to FlexQueryAsync:
using FlexQuery.NET;
// Program.cs — once, before any query executes
FlexQueryCore.Configure();
FlexQueryEFCore.Setup();using FlexQuery.NET.Models;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/customers")]
public sealed class CustomersController(AppDbContext db) : ControllerBase
{
[HttpGet]
public async Task<IActionResult> GetCustomers(
[FromQuery] FlexQueryParameters parameters,
CancellationToken cancellationToken)
{
var result = await db.Customers
.FlexQueryAsync(parameters, opt =>
{
opt.AllowedFields = ["Id", "FirstName", "LastName", "Email", "Status"];
opt.MaxPageSize = 100;
opt.DefaultSortField = "Id";
}, cancellationToken);
return Ok(result);
}
}That's the whole endpoint. A request like:
GET /api/customers?filter=Status:eq:Active&sort=LastName:asc&page=1&pageSize=20&select=Id,FirstName,Emailreturns a paged, validated, SQL-translated result:
{
"data": [
{ "id": 3, "firstName": "Ana", "email": "ana@example.com" }
],
"totalCount": 42,
"page": 1,
"pageSize": 20,
"totalPages": 3,
"hasNextPage": true,
"hasPreviousPage": false
}With an explicit select, the response contains exactly the requested fields — and nothing else.
The same endpoint can accept different filter syntaxes:
GET /api/customers?filter=Status:eq:Active # Native DSL (default)
GET /api/customers?filter=Status = 'Active' # FQL (SQL-inspired)
GET /api/customers?$filter=Status eq 'Active' # MiniOData (OData-compatible)The DSL supports the AND/OR keywords (and &/|), parentheses for grouping, and operators such as eq, neq, gt, gte, lt, lte, contains, startswith, endswith, like, in, notin, between, isnull, isnotnull, any, all, and count.
FQL and MiniOData parsers ship as separate packages and are enabled with a one-line registration at startup:
Fql.Register(); // FlexQuery.NET.Parsers.Fql
MiniOData.Register(); // FlexQuery.NET.Parsers.MiniODataSelect the syntax globally via FlexQueryOptions.DefaultQuerySyntax, or per request via the options' QuerySyntax property.
- Filtering — composable conditions with ~20 operators,
AND/ORlogic, and nesting. - Sorting — multi-field, per-field direction, with server-defined defaults.
- Selection & DTO projection — dynamic
selectwith aliases, or strongly-typed results viaFlexQueryAsync<TEntity, TResponse>with a convention-based mapping model (CreateMap,ForMember,ForNavigation). - Pagination — offset paging and high-performance keyset (cursor) pagination with
cursor/NextCursorToken. - Include & Expand — eager-load navigations, or deep expansions where each branch can carry its own filter, sort, and take.
- Grouping & aggregates —
groupBy,aggregate(sum, count, avg, …),having, anddistinct. - Validation & governance — per-operation field whitelists (
FilterableFields,SortableFields,SelectableFields, …), allowed-operator policies, field-depth limits, role-based field access, and secure-by-default strict validation. - Fluent API — compose queries in code with
Query.Create()and typed filter builders. - OpenAPI — document FlexQuery endpoints automatically in ASP.NET Core's built-in OpenAPI generation.
| Package | Purpose | README |
|---|---|---|
| FlexQuery.NET | Core query engine — parsing, filtering, sorting, paging, projection, grouping, validation, fluent API | docs |
| FlexQuery.NET.EntityFrameworkCore | Async execution, filtered includes, and typed DTO projection for EF Core | docs |
| FlexQuery.NET.Dapper | Direct SQL generation and execution for Dapper (SQL Server, PostgreSQL, MySQL, MariaDB, SQLite, Oracle) | docs |
| FlexQuery.NET.AspNetCore | ASP.NET Core integration with [FieldAccess] security attributes and result-shape JSON |
docs |
| FlexQuery.NET.OpenApi | OpenAPI/Swagger documentation for FlexQuery endpoints (.NET 9/10) | docs |
| FlexQuery.NET.Diagnostics | Execution diagnostics, timing, and observability | docs |
| FlexQuery.NET.Adapters.AgGrid | AG Grid Server-Side Row Model request/response adapter | docs |
| FlexQuery.NET.Adapters.Kendo | Kendo UI DataSource request adapter | docs |
| FlexQuery.NET.Parsers.Fql | FQL (SQL-inspired) syntax parser | docs |
| FlexQuery.NET.Parsers.MiniOData | Lightweight OData-compatible syntax parser | docs |
Every package ships with its own README — the same document included in its NuGet package — covering installation, quick-start snippets, and package-specific features. The links in the table above go to those READMEs; each one also cross-references the related packages.
All packages depend on the core package only; mix and match what you need:
graph TD
Core["FlexQuery.NET"]
Core --> EF["EntityFrameworkCore"]
Core --> Dapper["Dapper"]
Core --> AspNet["AspNetCore"]
Core --> OpenApi["OpenApi"]
Core --> Diag["Diagnostics"]
Core --> AgGrid["Adapters.AgGrid"]
Core --> Kendo["Adapters.Kendo"]
Core --> Fql["Parsers.Fql"]
Core --> OData["Parsers.MiniOData"]
The ASP.NET Core package adds declarative, attribute-based security on top of the governance options:
[FieldAccess(Allowed = ["Id", "FirstName", "Email"], Sortable = ["Id", "FirstName"])]
[HttpGet]
public async Task<IActionResult> Get(
[FromQuery] FlexQueryParameters parameters,
CancellationToken cancellationToken)
{
...
}Wire it up alongside global configuration:
builder.Services.AddControllersWithViews()
.AddFlexQuerySecurity(); // [FieldAccess] attributes + result-shape JSON
builder.Services.AddFlexQuery(options =>
{
options.MaxPageSize = 100;
options.StrictFieldValidation = true;
});Entity Framework Core — FlexQueryAsync (and the typed FlexQueryAsync<TEntity, TResponse> overload) executes the full pipeline — filter → sort → paging → includes → projection — as EF-translated expression trees, with CancellationToken support and no-tracking by default for read endpoints.
Dapper — generates and executes SQL directly against your DbConnection, with automatic dialect detection, an entity-mapping model builder, and SQL execution logging with copy-paste-ready DECLARE scripts:
var result = await connection.FlexQueryAsync<Customer>(parameters, cancellationToken: cancellationToken);The AG Grid and Kendo adapters translate grid requests into QueryOptions and convert results back, so a server-side grid endpoint is just a few lines:
var options = agGridRequest.ToQueryOptions(); // AG Grid SSRM request
var result = await db.Customers.FlexQueryAsync(options, cancellationToken: cancellationToken);
return Ok(result.ToAgGridServerSideResponse(agGridRequest));Full documentation for v4 lives at flexquery.vercel.app:
- Getting Started
- Query Syntax
- Filtering · Sorting · Paging · Keyset Pagination
- Projection · Typed DTO Projection
- Include · Expand
- Grouping & Aggregates
- Fluent API
- Security & Governance
- EF Core Provider · Dapper Provider
- ASP.NET Core · AG Grid · Kendo · OpenAPI
Coming from v3? v4 is a breaking release: packages were renamed (the JQL parser is now FQL), option classes were restructured, legacy query syntaxes were removed, and new capabilities such as typed DTO projection, expand, and keyset pagination were added. See the v3 → v4 migration guide.
A runnable sample Web API demonstrating EF Core, Dapper, AG Grid SSRM, and Kendo UI integrations is available in the samples folder.
MIT License. See LICENSE.