Param.QuerySpecification 2.0.1

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

Param.QuerySpecification

A powerful .NET 10 library implementing the Specification Pattern with dynamic filtering, sorting, paging, EF Core integration, and ASP.NET Core support.

NuGet License .NET

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 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

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
2.0.1 132 12/20/2025
2.0.0 128 12/20/2025

Version 2.0.1 - Removed Swashbuckle dependency, uses native .NET 10 OpenAPI support.