Working query in 10 minutes.
Add the package, define what's queryable, accept a JSON payload, call Execute(). That's it.
Install via NuGet
Supports .NET 6, 7, 8, 9, and 10
.NET CLI
dotnet add package ServiceQuery
Package Manager
Install-Package ServiceQuery
PackageReference
<PackageReference
Include="ServiceQuery" />
Your First Query
ServiceQuery works with any IQueryable — database tables, collections, or in-memory lists.
The Mental Model
You give ServiceQuery an IQueryable<T>.
It returns results after applying the request's filter/sort/page/aggregate.
No magic. No hidden schema.
using ServiceQuery;
// Get your database table as an IQueryable
var queryable = databaseContext.Products.AsQueryable();
// Or use in-memory lists
var list = new List<Product>
{
new Product { Id = 1, Name = "Widget", Price = 9.99m }
}.AsQueryable();
// Build a request
var request = new ServiceQueryRequestBuilder().Build();
// Execute and get results
var response = request.Execute(queryable);
// Async support
var responseAsync = await request.ExecuteAsync(queryable);
Use in a REST API
Add a query endpoint to any controller in just a few lines.
Minimal API
app.MapPost("/products/search",
(ServiceQueryRequest request, AppDb db) =>
{
var queryable = db.Products.AsQueryable();
return Results.Ok(request.Execute(queryable));
});
Controller
[HttpPost("query")]
public ServiceQueryResponse<ProductDto> Query(
ServiceQueryRequest request)
{
var queryable = _db.Products.AsQueryable();
return request.Execute(queryable);
}
JavaScript Client
Same builder pattern works in JavaScript. Include servicequery.js in your project.
Using Fetch
const request = new ServiceQueryRequestBuilder()
.IsEqual("Status", "Active")
.SortDesc("CreatedAt")
.Paging(1, 25)
.Build();
fetch('/api/products/query', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request)
})
.then(response => response.json())
.then(result => {
console.log(result.list.length + ' records');
});
Using jQuery
const request = new ServiceQueryRequestBuilder()
.IsEqual("Status", "Active")
.SortDesc("CreatedAt")
.Paging(1, 25)
.Build();
$.ajax({
url: '/api/products/query',
type: 'POST',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(request),
success: function(result) {
console.log(result.list.length + ' records');
}
});
Building Queries
The same code works in .NET or JavaScript. Here are common patterns:
// Default - returns all records with paging
var request = new ServiceQueryRequestBuilder().Build();
// Paging
request = new ServiceQueryRequestBuilder()
.Paging(1, 25, true) // page 1, 25 per page, include count
.Build();
// Aggregates (return aggregate values, not records)
request = new ServiceQueryRequestBuilder().Count().Build();
request = new ServiceQueryRequestBuilder().Sum("Price").Build();
request = new ServiceQueryRequestBuilder().Average("Price").Build();
request = new ServiceQueryRequestBuilder().Minimum("Price").Build();
request = new ServiceQueryRequestBuilder().Maximum("Price").Build();
// Select specific properties
request = new ServiceQueryRequestBuilder()
.Select("Id", "Name", "Price")
.Build();
// Filtering
request = new ServiceQueryRequestBuilder()
.IsEqual("Status", "Active")
.Build();
request = new ServiceQueryRequestBuilder()
.IsGreaterThan("Price", "100")
.Build();
request = new ServiceQueryRequestBuilder()
.Contains("Name", "widget")
.Build();
request = new ServiceQueryRequestBuilder()
.IsInSet("Status", "Open", "Pending", "InProgress")
.Build();
// AND / OR logic
request = new ServiceQueryRequestBuilder()
.IsEqual("Status", "Active")
.And()
.IsGreaterThan("Price", "50")
.Build();
// Grouped expressions with Begin() and End()
request = new ServiceQueryRequestBuilder()
.Begin()
.IsEqual("Status", "Active")
.Or()
.IsEqual("Status", "Pending")
.End()
.And()
.IsGreaterThan("Amount", "100")
.Build();
// Sorting
request = new ServiceQueryRequestBuilder()
.SortAsc("Category")
.SortDesc("Price")
.Build();
Async Support
Async execution requires provider-specific packages:
ServiceQuery.EntityFrameworkCore
For EF Core databases (SQL Server, PostgreSQL, MySQL, SQLite). Targets EF Core 9 / .NET 8+
ServiceQuery.EntityFrameworkCore8
For EF Core 8 / .NET 8 projects.
ServiceQuery.MongoDb
For MongoDB. Uses MongoDbExecuteAsync().
ServiceQuery.AzureDataTables
For Azure Data Tables. Includes workarounds for unsupported features.
Before You Ship
Start with paging limits. Don't ship a public endpoint with unlimited page size and then blame the query library when your database cries.
Review Security & GuardrailsNext Steps
Where to go from here.