Local build
July 25, 2026 · View on GitHub
This document explains how to restore, compile, and test AspectCore locally, and describes how multi-targeting and build properties (build props) are organized. All commands and configuration are based on the actual files in the repository root's AspectCore-Framework.sln and under build/, src/, and tests/.
1. Environment setup
The repository root has no global.json, so it does not pin a specific SDK version, but the target frameworks determine which SDKs you need to install:
- The test projects
AspectCore.Core.TestsandAspectCore.E2E.Teststargetnet10.0;net9.0;net8.0;net6.0. To compile and run the full test suite, you need the .NET 10 SDK installed. - The source packages target
net6.0at minimum, with additional targetsnet8.0/net9.0/net10.0(exceptAspectCore.SourceGenerator, which is anetstandard2.0Roslyn analyzer); running a multi-target build requires the corresponding .NET 6/8/9/10 runtimes. - CI explicitly installs the following SDKs via
actions/setup-dotnet:6.0.x,8.0.x,9.0.x,10.0.x(see.github/workflows/build-ci.ymland.github/workflows/build-pr-ci.yml). Aligning locally with these versions covers all target frameworks.
Verify your local SDKs:
dotnet --list-sdks
dotnet --version
2. Restore, compile, test (solution scope)
Operate on the whole solution from the repository root:
# Restore NuGet dependencies
dotnet restore AspectCore-Framework.sln
# Compile (Release, consistent with CI)
dotnet build AspectCore-Framework.sln -c Release
# Run all tests
dotnet test AspectCore-Framework.sln
CI does not call
dotnet buildon the solution directly; instead it iterates over every*.csprojunder./srcand./testsand runsbuild/testone by one (see theBuild/Run Testssteps inbuild-ci.yml). Solution-scope commands are more convenient locally; if you need to reproduce CI exactly, run at per-project granularity.
3. Running per project / by condition (a narrower scope)
When debugging a single module, point directly at the project file to avoid a full build:
# Build only the core package
dotnet build src/AspectCore.Core/AspectCore.Core.csproj -c Release
# Test only the core unit-test project
dotnet test tests/AspectCore.Core.Tests/AspectCore.Core.Tests.csproj
# Run only the dual-engine parity (EngineParity) cases
dotnet test tests/AspectCore.Core.Tests/AspectCore.Core.Tests.csproj \
--filter "FullyQualifiedName~EngineParity"
# Test on a single target framework to shorten the feedback loop
dotnet test tests/AspectCore.Core.Tests/AspectCore.Core.Tests.csproj -f net8.0
For more filtering and coverage-collection examples, see Running tests.
4. Notes on target frameworks
Different projects choose target frameworks by purpose; the authoritative source is each *.csproj:
| Project | Target frameworks | Notes |
|---|---|---|
AspectCore.Abstractions, AspectCore.Core, AspectCore.Extensions.Reflection | net10.0;net9.0;net8.0;net6.0 | The core packages multi-target, with net6.0 as the minimum |
AspectCore.SourceGenerator | netstandard2.0 | The compile-time engine must target netstandard2.0 for Roslyn to load; LangVersion=latest |
AspectCore.Extensions.AspNetCore | net10.0;net9.0;net8.0;net6.0 | net6.0 and above only |
| Container/host and other extension packages | Per each *.csproj: most are net10.0;net9.0;net8.0;net6.0, except AspectCore.Extensions.CastleCompat at net10.0;net9.0;net8.0 (no net6.0) | See Project structure and Module and package structure design |
| Test projects | Mostly net10.0;net9.0;net8.0;net6.0 or net9.0;net8.0;net6.0 | For the specific differences, see Testing strategy |
A multi-target build produces one assembly per target framework; therefore, missing a runtime locally will cause the compile or test step for that target framework to fail.
5. Build properties (build props) layout
Build configuration is centralized in the build/ directory and two Directory.Build.props, imported by each *.csproj via Import:
build/version.props— the product version. CurrentlyVersionMajor=3,VersionMinor=0,VersionPatch=0,VersionQuality=rc.1, soVersionPrefix=3.0.0andVersionSuffix=rc.1. When there is no Git tag, CI appends-preview-<timestamp>.build/common.props— common package metadata (Authors=Lemon,Product=AspectCore Framework, repository URL, etc.), and itImportssign.propsandversion.props. It setsLangVersion=13.0; the comment explains: 13.0 enables the Default Interface Methods, static abstract members, and other modern features needed for NativeAOT AOP support, while remaining compatible with the lowest target frameworknet6.0. The core package source is written under this constraint.build/sign.propsandbuild/aspectcore.snk— strong-name signing configuration and key.src/Directory.Build.props— enables .NET analyzers for all projects undersrc/(EnableNETAnalyzers=true,AnalysisLevel=latest,AnalysisMode=Default,EnforceExtendedAnalyzerRules=true). These are advisory diagnostics, not a hard failure gate.tests/Directory.Build.props— uniformly brings incoverlet.msbuild(version6.0.2,PrivateAssets=all) for all test projects, used for coverage collection.
The repository root has no
Directory.Build.props; thesrc/andtests/props apply only to their respective subdirectories.AspectCore.SourceGeneratorseparately overridesLangVersiontolatest.
Related docs
- Project structure — the layout of the source, test, sample, and benchmark directories
- Contributing guide — branch, commit, and PR process
- Running tests — test filtering and coverage collection
- Module and package structure design — the responsibilities and dependency directions of the 15 packages
- Docs home