AspectGenerator 0.1.0
dotnet add package AspectGenerator --version 0.1.0
NuGet\Install-Package AspectGenerator -Version 0.1.0
<PackageReference Include="AspectGenerator" Version="0.1.0" />
<PackageVersion Include="AspectGenerator" Version="0.1.0" />
<PackageReference Include="AspectGenerator" />
paket add AspectGenerator --version 0.1.0
#r "nuget: AspectGenerator, 0.1.0"
#:package AspectGenerator@0.1.0
#addin nuget:?package=AspectGenerator&version=0.1.0
#tool nuget:?package=AspectGenerator&version=0.1.0
Aspect Generator
AspectGenerator is a source generator for compile-time call-site rewriting with C# interceptors. It lets you define attribute-based aspects that run around intercepted method calls without runtime proxies or IL weaving.
AspectGenerator itself targets netstandard2.0, but consuming projects must be built with the .NET 10 SDK/compiler because the generator uses the stable Roslyn interceptor API based on opaque InterceptableLocation data. Older SDKs and the legacy InterceptsLocation(filePath, line, character) preview API are not supported.
This is not runtime AOP. Aspects are applied by rewriting call sites visible to the current compilation. Calls made through reflection, delegates, already-compiled external assemblies, or unsupported C# constructs are outside the interception model.
Quick Start
Install the package:
dotnet add package AspectGenerator
Configure the consuming project:
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<InterceptorsNamespaces>$(InterceptorsNamespaces);AspectGenerator</InterceptorsNamespaces>
</PropertyGroup>
Define an aspect:
using AspectGenerator;
namespace Aspects;
[Aspect(OnBeforeCall = nameof(OnBeforeCall))]
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
sealed class LogAttribute : Attribute
{
public static void OnBeforeCall(InterceptInfo info)
{
Console.WriteLine($"Calling {info.MemberInfo.Name}");
}
}
Use it on a method:
using Aspects;
class Service
{
[Log]
public static void DoWork()
{
}
}
Service.DoWork();
AspectGenerator finds interceptable call sites to DoWork in the current compilation and emits interceptor methods for those locations.
Configuration
AspectGenerator can be configured with MSBuild properties:
<PropertyGroup>
<AspectGeneratorGenerateApi>true</AspectGeneratorGenerateApi>
<AspectGeneratorPublicApi>false</AspectGeneratorPublicApi>
<AspectGeneratorDebuggerStepThrough>false</AspectGeneratorDebuggerStepThrough>
<AspectGeneratorInterceptorsNamespace>AspectGenerator</AspectGeneratorInterceptorsNamespace>
</PropertyGroup>
The same settings can be overridden with an assembly-level attribute:
using AspectGenerator;
[assembly: AspectGeneratorOptions(
GenerateApi = true,
PublicApi = false,
DebuggerStepThrough = false,
InterceptorsNamespace = "AspectGenerator")]
AspectGeneratorInterceptorsNamespace must also be listed in InterceptorsNamespaces, otherwise the compiler will not enable generated interceptors from that namespace.
Generated API Ownership
AspectGenerator normally generates the authoring/runtime API into each consuming compilation:
GenerateApi=true: generateAspectAttribute,InterceptInfo,InterceptData<T>,InterceptResult, and related types.GenerateApi=false: do not generate the API. Use this when the API is supplied by an aspect library.PublicApi=false: generated API is internal to the consuming assembly.PublicApi=true: generated API is public. Treat this mode as experimental until the public contract is stabilized.
Common modes:
| Mode | Configuration | Intended use |
|---|---|---|
| Single project | GenerateApi=true, PublicApi=false |
App defines and uses its own aspects. |
| Aspect library | Library: GenerateApi=true, PublicApi=true; consumer: GenerateApi=false |
Shared aspect attributes live in a reusable assembly. |
| Cross-project app | Same interceptor namespace in each project via AspectGeneratorInterceptorsNamespace and InterceptorsNamespaces |
Intercept calls compiled in multiple projects. |
Supported Scenarios
| Scenario | Status | Notes |
|---|---|---|
| Static methods | Supported | Ordinary member method calls only. |
| Instance methods | Supported | Call site must be visible to the current compilation. |
| Extension methods | Supported | Covered by unit tests. |
| Generic methods | Supported | Explicit InterceptMethods strings must match generated display names. |
Task and Task<T> async methods |
Supported | Async hooks are selected for Task targets. |
ref, out, in parameters |
Supported | Covered by unit tests. |
| Constructors | Unsupported | Platform limitation of C# interceptors. |
| Properties and indexers | Unsupported | Not ordinary method invocation syntax. |
| Operators | Unsupported | Not currently matched by the generator. |
| Delegates and reflection | Unsupported | No direct call site rewrite. |
| Local functions | Unsupported | Platform limitation. |
| Calls compiled in external assemblies | Unsupported | Rebuild the assembly containing the call site with AspectGenerator enabled. |
ValueTask and ValueTask<T> |
Not currently supported | Planned or explicitly documented as a limitation. |
Hooks
AspectAttribute maps lifecycle hooks to static method names:
[Aspect(
OnInit = nameof(OnInit),
OnUsing = nameof(OnUsing),
OnUsingAsync = nameof(OnUsingAsync),
OnBeforeCall = nameof(OnBeforeCall),
OnBeforeCallAsync = nameof(OnBeforeCallAsync),
OnCall = nameof(OnCall),
OnAfterCall = nameof(OnAfterCall),
OnAfterCallAsync = nameof(OnAfterCallAsync),
OnCatch = nameof(OnCatch),
OnCatchAsync = nameof(OnCatchAsync),
OnFinally = nameof(OnFinally),
OnFinallyAsync = nameof(OnFinallyAsync))]
Hook names are strings, so prefer nameof(...). Invalid names or signatures should be reported by AspectGenerator diagnostics; if a case still fails only through generated-code compiler errors, treat that as a bug.
Explicit Method Interception
InterceptMethods is a low-level compatibility feature that matches methods by display string:
[Aspect(
OnAfterCall = nameof(OnAfterCall),
InterceptMethods =
[
"System.String.Substring(int)",
"string.Substring(int)"
])]
This form is brittle because it depends on compiler display strings, aliases, overloads, and generic spelling. Prefer method-level aspect attributes where possible.
Documentation And Wiki
The README is the concise entry point. The wiki should contain expanded pages with the same current terminology:
When updating docs, keep README and wiki synchronized:
- document the .NET 10 SDK/compiler requirement and use
net10.0in examples; - use
InterceptorsNamespaces, notInterceptorsPreviewNamespaces; - use
AspectGeneratorGenerateApi,AspectGeneratorPublicApi,AspectGeneratorDebuggerStepThrough, andAspectGeneratorInterceptorsNamespace; - describe
InterceptableLocationas opaque compiler data; - keep unsupported scenarios consistent between README and wiki.
Any remaining preview-era wiki page should be updated or marked with an “Obsolete preview documentation” warning.
Development
Run the main checks locally:
dotnet restore
dotnet build --no-restore
dotnet test --no-build
dotnet pack Source/AspectGenerator.csproj --no-build
Build artifacts under bin/ and obj/ must not be committed. If generated source snapshots are needed, store them in an explicit baseline folder under UnitTests/, not under obj/GeneratedFiles.
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- No dependencies.
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 |
|---|---|---|
| 0.1.0 | 42 | 6/11/2026 |
| 0.0.9-preview | 384 | 12/28/2023 |
| 0.0.8-preview | 190 | 12/13/2023 |
| 0.0.7-preview | 145 | 12/12/2023 |
| 0.0.5-preview | 171 | 12/4/2023 |
| 0.0.4-preview | 165 | 11/27/2023 |
| 0.0.3-preview | 141 | 11/23/2023 |
| 0.0.1-preview | 135 | 11/22/2023 |