Param.QuerySpecification
2.0.1
dotnet add package Param.QuerySpecification --version 2.0.1
NuGet\Install-Package Param.QuerySpecification -Version 2.0.1
<PackageReference Include="Param.QuerySpecification" Version="2.0.1" />
<PackageVersion Include="Param.QuerySpecification" Version="2.0.1" />
<PackageReference Include="Param.QuerySpecification" />
paket add Param.QuerySpecification --version 2.0.1
#r "nuget: Param.QuerySpecification, 2.0.1"
#:package Param.QuerySpecification@2.0.1
#addin nuget:?package=Param.QuerySpecification&version=2.0.1
#tool nuget:?package=Param.QuerySpecification&version=2.0.1
Param.QuerySpecification
A powerful .NET 10 library implementing the Specification Pattern with dynamic filtering, sorting, paging, EF Core integration, and ASP.NET Core support.
Features
- Specification Pattern: Build reusable, composable, type-safe query specifications
- Dynamic Filtering: Kendo-style JSON filters with complex nested conditions
- Sorting & Paging: Built-in support for paginated results with multi-field sorting
- EF Core Integration: Optimized for Entity Framework Core with Include support
- ASP.NET Core Support: Automatic model binding for query parameters
- High Performance: Expression caching, property caching, optimized for speed
- .NET 10: Built for the latest .NET with modern C# features
Installation
dotnet add package Param.QuerySpecification
Quick Start
Define a Specification
using Param.QuerySpecification.Specifications;
public class ActiveUsersSpec : Specification<User>
{
public override Expression<Func<User, bool>> ToExpression()
=> user => user.IsActive && !user.IsDeleted;
}
Use with LINQ
using Param.QuerySpecification.Extensions;
var activeUsers = await dbContext.Users
.Where(new ActiveUsersSpec())
.ToListAsync();
// Combine specifications
var activePremiumUsers = await dbContext.Users
.Where(new ActiveUsersSpec().And(new PremiumUsersSpec()))
.ToListAsync();
ASP.NET Core API with Filtering
using Param.QuerySpecification.Attributes;
using Param.QuerySpecification.Extensions;
using Param.QuerySpecification.Models;
[HttpGet]
public async Task<PagedResult<UserDto>> GetUsers([FromPagedQuery] PagedRequest request)
{
return await _dbContext.Users
.ApplyFiltering(request)
.ApplySorting(request)
.ToPagedResultAsync(request, user => new UserDto
{
Id = user.Id,
Email = user.Email,
FullName = $"{user.FirstName} {user.LastName}"
});
}
Client-Side Query
const response = await fetch('/api/users?' + new URLSearchParams({
page: 1,
pageSize: 20,
'sort[0].field': 'lastName',
'sort[0].direction': 'Ascending',
'filter.field': 'email',
'filter.operator': 'Contains',
'filter.value': '@example.com'
}));
const result = await response.json();
// { items: [...], totalCount: 150, page: 1, pageSize: 20, totalPages: 8 }
Namespaces
| Namespace | Purpose |
|---|---|
Param.QuerySpecification.Specifications |
Core specification classes (Specification<T>, combinators) |
Param.QuerySpecification.Models |
Filter, sort, and paging models |
Param.QuerySpecification.Builders |
Expression builders for filters and sorting |
Param.QuerySpecification.Extensions |
LINQ and IQueryable extensions |
Param.QuerySpecification.EntityFramework |
EF Core specific extensions |
Param.QuerySpecification.Attributes |
ASP.NET Core attributes ([FromPagedQuery]) |
Param.QuerySpecification.ModelBinders |
Custom model binders |
Param.QuerySpecification.Validation |
Filter validation |
Param.QuerySpecification.Exceptions |
Custom exceptions |
Key Concepts
Specification Pattern
Encapsulate business rules into reusable, testable objects:
// Simple specification
public class PremiumUsersSpec : Specification<User>
{
public override Expression<Func<User, bool>> ToExpression()
=> user => user.SubscriptionType == SubscriptionType.Premium;
}
// Parameterized specification
public class UsersByRoleSpec : Specification<User>
{
private readonly string _role;
public UsersByRoleSpec(string role) => _role = role;
public override Expression<Func<User, bool>> ToExpression()
=> user => user.Role == _role;
}
// Combine specifications
var eligibleUsers = new ActiveUsersSpec()
.And(new PremiumUsersSpec())
.Or(new TrialUsersSpec());
Dynamic Filtering
Build complex filters from JSON/query strings:
using Param.QuerySpecification.Models;
using Param.QuerySpecification.Builders;
var filter = new FilterDescriptor
{
Logic = LogicOperator.And,
Filters = new List<FilterDescriptor>
{
new() { Field = "IsActive", Operator = FilterOperator.Equals, Value = true },
new() { Field = "Email", Operator = FilterOperator.Contains, Value = "@example.com" },
new() { Field = "Age", Operator = FilterOperator.GreaterThanOrEqual, Value = 18 }
}
};
var expression = FilterExpressionBuilder.Build<User>(filter);
var users = await dbContext.Users.Where(expression).ToListAsync();
Supported Filter Operators
- Comparison:
Equals,NotEquals,GreaterThan,GreaterThanOrEqual,LessThan,LessThanOrEqual - String:
Contains,NotContains,StartsWith,EndsWith - Array:
In,NotIn - Null:
IsNull,IsNotNull
EF Core Integration
using Param.QuerySpecification.EntityFramework;
// With Include support
public class UserWithOrdersSpec : EFCoreSpecification<User>
{
public UserWithOrdersSpec()
{
AddInclude(u => u.Orders);
AddInclude("Orders.OrderItems");
}
public override Expression<Func<User, bool>> ToExpression()
=> user => user.IsActive;
}
ASP.NET Core Setup
// Program.cs
using Param.QuerySpecification.Extensions;
builder.Services.AddQuerySpecification();
Testing
Specifications are easy to test in isolation:
[Fact]
public void ActiveUsersSpec_ShouldReturnOnlyActiveUsers()
{
var spec = new ActiveUsersSpec();
var activeUser = new User { IsActive = true, IsDeleted = false };
var inactiveUser = new User { IsActive = false };
Assert.True(spec.IsSatisfiedBy(activeUser)); // Cached for performance
Assert.False(spec.IsSatisfiedBy(inactiveUser));
}
Requirements
- .NET 10.0+
- Entity Framework Core 10.0+ (for EF Core features)
- ASP.NET Core 10.0+ (for ASP.NET Core features)
Documentation
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
Made with ❤️ for the .NET community
| Product | Versions 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. |
-
net10.0
- Microsoft.EntityFrameworkCore (>= 10.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version 2.0.1 - Removed Swashbuckle dependency, uses native .NET 10 OpenAPI support.