This document describes the multi-targeting strategy employed by Audit.NET to support a wide range of .NET Framework and .NET Core/5+ versions across 47+ packages. It covers conditional compilation directives, shared source code patterns, and framework-specific dependency management.
For information about the build and packaging process, see Build and Packaging. For testing strategies across different frameworks, see Testing Strategy.
Audit.NET supports nine target frameworks in its core package and various subsets across extension packages. The framework uses two primary techniques to achieve this breadth of compatibility:
<TargetFrameworks> in their project files, causing the build system to produce separate assemblies for each target#if, #elif, #endif) to include or exclude code based on framework-specific symbolsThis approach allows the codebase to support both legacy .NET Framework 4.6.2 applications and modern .NET 10 applications from a single source tree.
The following table shows the target frameworks supported by key packages in the ecosystem:
| Package | .NET Framework | .NET Standard | .NET Core/5+ |
|---|---|---|---|
| Audit.NET | net462, net472 | netstandard2.0, netstandard2.1 | net6.0, net7.0, net8.0, net9.0, net10.0 |
| Audit.EntityFramework | net462, net472 | netstandard2.1 | net6.0 |
| Audit.EntityFramework.Core | - | netstandard2.1 | net6.0, net7.0, net8.0, net9.0, net10.0 |
| Audit.WebApi | net462 | - | - |
| Audit.Mvc | net462 | - | - |
| Audit.WCF | net462 | - | - |
| Audit.NET.SqlServer | net462 | netstandard2.0, netstandard2.1 | net6.0, net7.0, net8.0, net9.0 |
| Audit.NET.MongoDB | net462, net472 | netstandard2.0, netstandard2.1 | net6.0 |
| Audit.NET.MySql | net462 | netstandard2.0 | net6.0 |
| Audit.NET.Redis | net462 | netstandard2.0 | net6.0 |
| Audit.DynamicProxy | net462 | netstandard2.0 | net6.0 |
| Audit.NET.Udp | net462 | netstandard2.0 | - |
Sources: src/Audit.NET/Audit.NET.csproj8 src/Audit.EntityFramework/Audit.EntityFramework.csproj8 src/Audit.EntityFramework.Core/Audit.EntityFramework.Core.csproj8
Diagram: Target Framework Selection Flow
The decision tree above shows how packages determine which frameworks to target based on their requirements and dependencies.
Sources: src/Audit.NET/Audit.NET.csproj8 src/Audit.EntityFramework.Core/Audit.EntityFramework.Core.csproj8
The codebase uses several top-level symbols to distinguish between platform families:
| Symbol | Purpose | Set By |
|---|---|---|
EF_FULL | Entity Framework 6.x (System.Data.Entity) | Audit.EntityFramework.csproj29 |
EF_CORE | Entity Framework Core | Audit.EntityFramework.Core.csproj9 |
ASP_NET | ASP.NET Framework (System.Web) | Audit.WebApi.csproj29 Audit.Mvc.csproj29 |
ASP_CORE | ASP.NET Core | Audit.WebApi.Core, Audit.Mvc.Core projects |
STRONG_NAME | Strong-name signing enabled | Most projects |
The Audit.EntityFramework.Core project defines progressive version symbols to enable or disable features based on the minimum EF Core version:
Diagram: EF Core Version Symbol Hierarchy
Each target framework gets cumulative version symbols. For example, net8.0 receives all symbols from EF_CORE_5 through EF_CORE_8_OR_GREATER.
Sources: src/Audit.EntityFramework.Core/Audit.EntityFramework.Core.csproj28-45
The version-specific symbols are defined in the project file using conditional property groups:
Sources: src/Audit.EntityFramework.Core/Audit.EntityFramework.Core.csproj28-45
Several packages share the same source code but compile it with different symbols to produce platform-specific variants. The most prominent example is the Entity Framework integration:
Diagram: Entity Framework Shared Source Architecture
The Audit.EntityFramework.Core project includes all source files from the Audit.EntityFramework directory:
Sources: src/Audit.EntityFramework.Core/Audit.EntityFramework.Core.csproj52
This allows a single set of source files to be compiled twice:
Audit.EntityFramework.dll with EF_FULL defined, referencing Entity Framework 6Audit.EntityFramework.Core.dll with EF_CORE defined, referencing Entity Framework CoreWithin the shared source, conditional compilation directives handle platform differences:
Sources: Shared source pattern at src/Audit.EntityFramework.Core/Audit.EntityFramework.Core.csproj52
The same pattern applies to web frameworks:
| Legacy Package | Modern Package | Shared Symbol |
|---|---|---|
Audit.WebApi | Audit.WebApi.Core | ASP_NET vs ASP_CORE |
Audit.Mvc | Audit.Mvc.Core | ASP_NET vs ASP_CORE |
Sources: src/Audit.WebApi/Audit.WebApi.csproj29 src/Audit.Mvc/Audit.Mvc.csproj29
The Audit.EntityFramework.Core project references different versions of Entity Framework Core based on the target framework:
Diagram: EF Core Version Mapping by Target Framework
This is accomplished through conditional ItemGroup elements in the project file:
Sources: src/Audit.EntityFramework.Core/Audit.EntityFramework.Core.csproj61-87
The Audit.NET.SqlServer package similarly varies its EF Core dependencies:
| Target Framework | EF Core Version | SQL Client Version |
|---|---|---|
| net462 | 3.1.32 | (built-in) |
| netstandard2.0 | 3.1.32 | (built-in) |
| netstandard2.1 | 5.0.17 | (built-in) |
| net6.0 | 6.0.36 | (built-in) |
| net7.0 | 7.0.20 | Microsoft.Data.SqlClient 5.2.2 |
| net8.0 | 8.0.11 | Microsoft.Data.SqlClient 5.2.2 |
| net9.0 | 9.0.0 | Microsoft.Data.SqlClient 5.2.2 |
Sources: src/Audit.NET.SqlServer/Audit.NET.SqlServer.csproj37-65
The Audit.NET.MongoDB package uses different MongoDB driver versions based on framework capabilities:
Sources: src/Audit.NET.MongoDB/Audit.NET.MongoDB.csproj30-40
This approach ensures:
net462 uses an older, compatible driver version (2.13.3)netstandard2.0 uses a newer version that still supports the API surface (2.30.0)net472, netstandard2.1, net6.0) use the latest driver (3.2.1)The Audit.NET core package includes polyfill packages for older frameworks to provide modern APIs:
Sources: src/Audit.NET/Audit.NET.csproj40-47
These packages provide:
Microsoft.Bcl.AsyncInterfaces: IAsyncEnumerable<T> and related async interfaces for .NET Standard 2.0System.Text.Json: Modern JSON serialization for all non-.NET 6+ frameworksSystem.Diagnostics.DiagnosticSource: Activity support for distributed tracingThe Audit.EntityFramework package includes System.Text.Json for all targets except net6.0:
Sources: src/Audit.EntityFramework/Audit.EntityFramework.csproj61-63
The Audit.EntityFramework.Core package includes it only for netstandard2.1:
Sources: src/Audit.EntityFramework.Core/Audit.EntityFramework.Core.csproj61-66
Packages targeting .NET Framework 4.6.2 or 4.7.2 often require explicit references to framework assemblies:
Sources: src/Audit.EntityFramework/Audit.EntityFramework.csproj46-51
Common system assemblies referenced:
System.Data: Database access (ADO.NET)System.Transactions: Transaction managementSystem.ServiceModel: WCF servicesSystem.Web: ASP.NET pipelineSystem.Configuration: Configuration file accessMicrosoft.CSharp: Dynamic binding supportThe Audit.WCF package requires WCF-specific assemblies only available in .NET Framework:
Sources: src/Audit.WCF/Audit.WCF.csproj37-42
Most packages in the Audit.NET ecosystem use strong-name signing for assembly identity and security:
Sources: src/Audit.NET/Audit.NET.csproj9-15
The STRONG_NAME symbol is defined to enable conditional compilation of strong-name-specific code. On non-Windows platforms, public signing is used instead of full strong-name signing due to tooling limitations.
Sources: Multiple .csproj files including src/Audit.NET.SqlServer/Audit.NET.SqlServer.csproj9-15 src/Audit.EntityFramework/Audit.EntityFramework.csproj9-15
Diagram: Target Framework Decision Tree by Package Type
Examples:
net462 only, SignalR Core is modern only)Sources: Analysis of project files across src/Audit.NET/ src/Audit.NET.SqlServer/ src/Audit.WCF/
When a multi-targeted package is built, the output contains separate assemblies for each target framework:
Audit.NET.nupkg
├── lib/
│ ├── net462/
│ │ └── Audit.NET.dll
│ ├── net472/
│ │ └── Audit.NET.dll
│ ├── netstandard2.0/
│ │ └── Audit.NET.dll
│ ├── netstandard2.1/
│ │ └── Audit.NET.dll
│ ├── net6.0/
│ │ └── Audit.NET.dll
│ ├── net7.0/
│ │ └── Audit.NET.dll
│ ├── net8.0/
│ │ └── Audit.NET.dll
│ ├── net9.0/
│ │ └── Audit.NET.dll
│ └── net10.0/
│ └── Audit.NET.dll
NuGet automatically selects the most appropriate assembly based on the consuming project's target framework, following its framework compatibility rules.
Sources: src/Audit.NET/Audit.NET.csproj8
The Audit.NET codebase employs several sophisticated strategies to maintain broad framework compatibility:
| Strategy | Technique | Examples |
|---|---|---|
| Maximum Compatibility | Target 9 frameworks in core package | Audit.NET.csproj8 |
| Platform Discrimination | Separate packages with shared source | EntityFramework vs EntityFramework.Core |
| Conditional Compilation | #if EF_CORE / #if EF_FULL | Throughout EntityFramework source |
| Version Detection | Progressive EF_CORE_X_OR_GREATER symbols | EntityFramework.Core.csproj28-45 |
| Dependency Versioning | Conditional PackageReference by framework | SqlServer.csproj37-65 |
| Polyfill Packages | Add modern APIs to older frameworks | Audit.NET.csproj40-47 |
| Legacy Framework Support | Explicit System.* assembly references | EntityFramework.csproj46-51 |
This multi-layered approach allows the framework to maintain a single source tree while producing optimized builds for each supported platform, from .NET Framework 4.6.2 applications to cutting-edge .NET 10 services.
Refresh this wiki