Skip to content
Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Latest commit

 

History

55 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

QueryGuard.NET logo

QueryGuard.NET

Your endpoint returns 200 OK. It also ran the same query 51 times.

NuGet CI Documentation License: MIT Targets .NET 8 and .NET 10

QueryGuard fails a query budget for GET /api/companies after one fingerprint runs 50 times.

QueryGuard counts the EF Core queries that your code runs, groups repeated SQL, and lets a test fail before an N+1 regression reaches production.

It reports repeated-query candidates, not proof. Some repetition is correct. Intentional cases stay visible with a written reason.

Quick start

For an ASP.NET Core integration test, install the WebApplicationFactory helper:

dotnet add package QueryGuard.AspNetCore.Testing

Open a measurement, run the request, and assert the result:

using var factory = new WebApplicationFactory<Program>();
await using var guard = factory.TrackQueries<Program, AppDbContext>(
    "GET /api/companies",
    QueryGuardPolicy.Create("companies")
        .WithMaxOccurrencesPerFingerprint(5));

var response = await guard.Client.GetAsync("/api/companies");
response.EnsureSuccessStatusCode();

QueryGuardAssert.Passes(await guard.CompleteAsync());

The helper attaches QueryGuard to AppDbContext, preserves the test execution context, and prevents request middleware from opening a second scope. It has no test framework dependency, so it works with xUnit, NUnit, MSTest, and TUnit.

Testing a service or background job without WebApplicationFactory? Install QueryGuard.Testing, attach .UseQueryGuard() where the context is configured, and open an explicit QueryGuardScope. See the testing guide for both paths.

Package Use it for
QueryGuard.AspNetCore.Testing Measuring real WebApplicationFactory requests
QueryGuard.Testing Explicit scopes and assertions around services or jobs
QueryGuard.AspNetCore Request middleware and route policies
QueryGuard.Reporting Console, JSON, JUnit, Markdown, and SARIF output
QueryGuard.Cli Recording and checking baselines in CI

Useful failures

QueryGuard FAILED: GET /api/companies (policy 'companies')
  51 read queries in 2 distinct queries

  [FAIL] max-occurrences-per-fingerprint: QG-FP-FDB5F469 executed 50 times; the budget is 5.
          SQL: SELECT COUNT(*) FROM "Departments" AS "d" WHERE "d"."CompanyId" = ?
          origin: samples/QueryGuard.SampleApi/Program.cs:line 89

The report shows the repeated fingerprint, normalized SQL, and the application line that ran it. Stack traces are captured once per distinct query in explicit test scopes. They stay off by default on request paths because they are much more expensive than normal capture.

Baselines

If you do not know the right budget yet, record current behavior and compare it in CI:

dotnet tool install -g QueryGuard.Cli

queryguard baseline record
queryguard verify --summary artifacts/queryguard/summary.md

Add --fail-on-regression when a regression should fail the build. Without it, the tool reports the change and exits successfully.

Publish the Markdown table as a job summary and sticky pull request comment:

- uses: Benziza/queryguard-dotnet@v0.1.0
  with:
    summary-path: artifacts/queryguard/summary.md

See the baseline guide and action guide.

Support matrix

Component Support
.NET .NET 8 and .NET 10
EF Core EF Core 8 and EF Core 10
Providers tested with real databases SQLite, PostgreSQL, SQL Server, MySQL
Other providers Any relational EF Core provider through DbCommandInterceptor

MySQL tests use Oracle's MySql.EntityFrameworkCore. Pomelo does not have an EF Core 10 release yet. See provider support for the exact claim and current caveats.

Tested in public projects

0.1.0-preview.6 was added to three public ASP.NET Core test suites before the stable release:

Project Test stack Request Result
CleanArchitecture NUnit, SQLite POST /api/Users/register 1 query, 1 group
SSW.VerticalSliceArchitecture xUnit, SQL Server GET /api/heroes 2 queries, 2 groups
CleanArchitecture NUnit, SQL Server GET /api/v1/Tenant/{id} 2 queries, 2 groups

All three request tests passed with no repeated-query finding. The validation notes include the setup, the package compatibility problem the work found, and the limits of this check.

Scope and privacy

QueryGuard is focused on query-count regressions.

  • It does not prove an N+1.
  • It does not observe Dapper or raw ADO.NET.
  • It does not collect execution plans or provide a profiler UI.
  • It does not rewrite queries or change HTTP responses.
  • The 0.1 public API is stable within the 0.1 release line. The project has not reached 1.0.0.

Parameter values and connection strings are not captured. Redaction runs before any reporter receives SQL. The JSON report has a schemaVersion so format changes are explicit.

Try the sample

git clone https://github.com/Benziza/queryguard-dotnet.git
cd queryguard-dotnet
dotnet test samples/QueryGuard.SampleTests

The sample includes a 51-query endpoint, a one-query fix, a baseline comparison, and an intentional repetition with an allowlist reason.

Documentation

Full documentation and the generated API reference are available at benziza.github.io/queryguard-dotnet.

Guide Covers
How it works Sessions, fingerprints, redaction, analysis
Testing WebApplicationFactory requests and explicit scopes
Public validation Results from three public ASP.NET Core projects
Configuration Budgets and defaults
Baselines Recording and comparing query behavior
Troubleshooting Missing capture, grouping, middleware order
False positives Allowlisting with a reason
Benchmarks Methodology and raw output
Decision records Design decisions and tradeoffs
API reference Every public type

Contributing

Issues and focused pull requests are welcome. Small fixes can go straight to a pull request. Open an issue first for public API, capture, privacy, or detector changes. See CONTRIBUTING.md.

False-positive reports are especially useful because they improve the defaults and become regression fixtures. Report security issues through SECURITY.md, not a public issue.

License

MIT. The project takes product inspiration from Bullet for Rails. The implementation is independent and uses EF Core's public interception API.

About

Detect repeated EF Core queries, enforce query budgets, and fail tests before N+1 regressions reach production.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

9 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages