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.Tests and AspectCore.E2E.Tests target net10.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.0 at minimum, with additional targets net8.0/net9.0/net10.0 (except AspectCore.SourceGenerator, which is a netstandard2.0 Roslyn 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.yml and .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 build on the solution directly; instead it iterates over every *.csproj under ./src and ./tests and runs build/test one by one (see the Build/Run Tests steps in build-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:

ProjectTarget frameworksNotes
AspectCore.Abstractions, AspectCore.Core, AspectCore.Extensions.Reflectionnet10.0;net9.0;net8.0;net6.0The core packages multi-target, with net6.0 as the minimum
AspectCore.SourceGeneratornetstandard2.0The compile-time engine must target netstandard2.0 for Roslyn to load; LangVersion=latest
AspectCore.Extensions.AspNetCorenet10.0;net9.0;net8.0;net6.0net6.0 and above only
Container/host and other extension packagesPer 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 projectsMostly net10.0;net9.0;net8.0;net6.0 or net9.0;net8.0;net6.0For 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. Currently VersionMajor=3, VersionMinor=0, VersionPatch=0, VersionQuality=rc.1, so VersionPrefix=3.0.0 and VersionSuffix=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 it Imports sign.props and version.props. It sets LangVersion=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 framework net6.0. The core package source is written under this constraint.
  • build/sign.props and build/aspectcore.snk — strong-name signing configuration and key.
  • src/Directory.Build.props — enables .NET analyzers for all projects under src/ (EnableNETAnalyzers=true, AnalysisLevel=latest, AnalysisMode=Default, EnforceExtendedAnalyzerRules=true). These are advisory diagnostics, not a hard failure gate.
  • tests/Directory.Build.props — uniformly brings in coverlet.msbuild (version 6.0.2, PrivateAssets=all) for all test projects, used for coverage collection.

The repository root has no Directory.Build.props; the src/ and tests/ props apply only to their respective subdirectories. AspectCore.SourceGenerator separately overrides LangVersion to latest.