AspectCore Framework Documentation

repository·master·Indexed 23 days ago

https://github.com/dotnetcore/aspectcore-framework

A cross-platform Aspect-Oriented Programming (AOP) framework for .NET 6+ that enables the implementation of cross-cutting concerns like logging, validation, and interception. It features two proxy generation engines: a DynamicProxy runtime engine using Reflection.Emit and a Source Generator compile-time engine based on Roslyn. AspectCore integrates with Microsoft.Extensions.DependencyInjection and other third-party containers such as Autofac, Windsor, and LightInject.

Tokens
72.9K
Snippets
129
Records
302
Agent score
82%

What's inside AspectCore

  1. Overview of AspectCore Repository Structure

    master

    The AspectCore repository is organized into several top-level directories that separate source code, tests, samples, and build configurations. Understanding this layout helps in locating specific packages, running examples, or contributing to the project.

    Directory Layout

    DirectoryPurpose
    src/Contains 15 publishable source packages (Core, Extensions, and Compile-time engines).
    tests/xUnit test projects covering unit tests, engine parity, E2E, reflection, and container integrations. Includes NativeAOT verification.
    sample/Runnable sample projects demonstrating typical usage patterns.
    benchmark/Legacy BenchmarkDotNet projects (Core, Reflection).
    benchmarks/The unified benchmark project: AspectCore.Benchmarks.
    docs/Project documentation (English available in docs/en/).
    build/Build configurations, including versioning, signing, and common package properties.
    .github/CI workflows and coverage scripts.

    Root Files

    • AspectCore-Framework.sln: The main solution file.
    • NuGet.config: NuGet configuration.
    • LICENSE: Project license.
    • README.md: Project overview.
  2. What is AspectCore Framework?

    master

    AspectCore is a cross-platform Aspect-Oriented Programming (AOP) framework designed for .NET 6+. It enables developers to implement cross-cutting concerns through dynamic-proxy interception. Key capabilities include:

    • Dynamic-proxy interception: Intercepting method calls at runtime.
    • Dependency Injection (DI) integration: Works with its own built-in container and Microsoft.Extensions.DependencyInjection.
    • Web application support: Integration with modern web frameworks.
    • Data validation: Intercepting calls to perform validation (e.g., via DataAnnotations).
    • Advanced AOP features: Support for async interception (Task, ValueTask, IAsyncEnumerable), conditional interception (matching by namespace, service, or method), and high-performance reflection.
  3. Overview of AspectCore Framework

    master

    AspectCore is a cross-platform framework for .NET 6+ designed around Aspect-Oriented Programming (AOP). It provides core support for:

    • Aspect-interceptor: Intercepting method calls to add cross-cutting concerns.
    • Dependency Injection (DI) integration: Seamlessly working with various IoC containers.
    • Web applications: Support for modern web development patterns.
    • Data validation: Integrating validation logic via aspects.
    • Dynamic Proxy: Providing proxy capabilities for intercepted objects.
  4. Understand AspectCore Source Generator Diagnostics (ACSGxxx)

    master

    AspectCore's Source Generator (the compile-time engine) generates proxy source code for types marked with [AspectCoreGenerateProxy]. If a target type or its members use forms that the generator cannot support, it reports a diagnostic with an ACSGxxx code.

    Diagnostic Details

    • Category: AspectCore.SourceGenerator (enabled by default).
    • Severity Levels:
      • Error: Blocks proxy generation for that type. In pure NativeAOT or trimming scenarios, these errors prevent AOP capabilities for that type.
      • Warning: Skips proxy generation for the type/member (without breaking compilation) or warns about runtime degradation (e.g., falling back to reflection).

    Diagnostic Summary Table

    IDTitleSeverityTriggerNativeAOT Impact
    ACSG001Open generic types not supportedWarningOpen generic typesIndirect (Currently supported)
    ACSG002Nested types not supportedWarningNested typesIndirect
    ACSG003Event members not supportedWarningTypes with event membersIndirect
    ACSG004Open generic methods not supportedWarningOpen generic methodsIndirect (Currently supported)
    ACSG005Cannot generate proxy for sealed typesErrorsealed classesYes (Blocks)
    ACSG006Type invisible to Source GeneratorErrorNon-public/internal typesYes (Blocks)
    ACSG007Type lacks accessible constructorErrorMissing accessible constructorYes (Blocks)
    ACSG008Cannot generate proxy for ref structsErrorref structYes (Blocks)
    ACSG009byref-like params not supportedWarningparams with byref-like typesYes
    ACSG010byref-like parameters not supportedWarningbyref-like parametersYes
    ACSG011byref-like return values not supportedWarningbyref-like return valuesYes
    ACSG0101Open generic methods fallback to reflection in NativeAOTWarningUnwarned open generic methodsYes (Direct)
  5. Overview of AspectCore package roles

    master

    AspectCore is distributed via 15 publishable source packages categorized into three primary roles:

    1. Core: Provides the fundamental interception logic.

      • AspectCore.Abstractions
      • AspectCore.Core
      • AspectCore.Extensions.Reflection
    2. Compile-time engine: Provides Roslyn-based source generation for interception.

      • AspectCore.SourceGenerator (targets netstandard2.0)
    3. Extensions and integrations: Provides support for specific DI containers, hosting models, and features.

      • DI Containers: AspectCore.Extensions.Autofac, AspectCore.Extensions.Windsor, AspectCore.Extensions.LightInject, AspectCore.Extensions.DependencyInjection.
      • Hosting & Web: AspectCore.Extensions.Hosting, AspectCore.Extensions.AspNetCore.
      • Features: AspectCore.Extensions.Configuration, AspectCore.Extensions.DataValidation, AspectCore.Extensions.DataAnnotations, AspectCore.Extensions.AspectScope.
      • Migration: AspectCore.Extensions.CastleCompat (a shim for gradual migration from Castle DynamicProxy to AspectCore).
  6. What is an Interceptor in AspectCore

    master

    An Interceptor is the unit that carries Aspect (AOP) logic, such as logging, caching, or transactions. It implements the IInterceptor interface and revolves around the Invoke method.

    The Invoke Method

    Task Invoke(AspectContext context, AspectDelegate next);
    • Before next(context): Logic executed before the target method runs.
    • After next(context): Logic executed after the target method returns.
    • Short-circuiting: If you do not call next(context), the original method is skipped (short-circuited).

    Ways to define Interceptors

    • AbstractInterceptorAttribute: An attribute that can be applied directly to interfaces, classes, or methods.
    • AbstractInterceptor: A base class typically used for global registration (not used as an attribute).
    • ServiceInterceptorAttribute: Resolves the actual interceptor instance from the container; ideal for interceptors requiring constructor injection.
    • Delegate Interceptor: Register a piece of logic directly using AddDelegate((ctx, next) => ...) without defining a new type.
  7. Overview of AspectCore layering and dependencies

    master

    AspectCore is organized into layers to maintain a unidirectional and acyclic dependency flow:

    • Foundation Layer:
      • AspectCore.Abstractions: Contains only contracts (interfaces, abstract classes, attributes, enums). No implementation.
      • AspectCore.Extensions.Reflection: A standalone high-performance reflection library used by the core.
    • Runtime Core Layer (AspectCore.Core):
      • Implements the DynamicProxy runtime engine, the IoC container (ServiceContext/ServiceResolver), and the interceptor pipeline. Depends on Abstractions and Reflection.
    • Integration/Feature Layer:
      • Contains DI adapters (e.g., DependencyInjection, Autofac, Windsor, LightInject, Hosting) and Web integrations (AspNetCore).
      • Contains features like AspectScope, DataValidation, DataAnnotations, and Configuration.
    • Compile-time Engine (AspectCore.SourceGenerator):
      • A standalone Roslyn analyzer that generates C# proxy source code at compile time. It has no project dependencies but generates code that references Core and Abstractions at runtime.
  8. Compare AspectCore vs Castle DynamicProxy features

    master

    When deciding between AspectCore and Castle DynamicProxy, consider the following key differences:

    Async Support

    • AspectCore: Provides native support for Task<T>, ValueTask<T>, and IAsyncEnumerable<T>. It uses a unified interceptor model for both sync and async.
    • Castle DynamicProxy: Requires an IAsyncInterceptor wrapper for Task<T> and lacks support for ValueTask<T> and IAsyncEnumerable<T>.

    Modern C# and AOT

    • AspectCore: Supports modern C# features like ref/ref readonly returns, Record types, Primary constructors (C# 12), and Partial properties (C# 13). It is NativeAOT compatible and trimming-safe via its Source Generator engine.
    • Castle DynamicProxy: Relies on runtime IL emission (Reflection.Emit) and does not support NativeAOT or Source Generation.

    Dependency Injection

    • AspectCore: Features native integration with Microsoft.Extensions.DependencyInjection, including support for Keyed services (.NET 8+) and ASP.NET Core IHost via AddDynamicProxy().
    • Castle DynamicProxy: Requires bridges like Autofac or Windsor for MSDI integration.

    Interceptor Configuration

    • AspectCore: Offers advanced configuration including AbstractInterceptorAttribute for attribute-based selection, AspectPredicate for global predicate-based configuration, an explicit Order property for interceptor ordering, and a [NonAspect] attribute to opt-out of interception.
    • Castle DynamicProxy: Has limited attribute-based selection and requires manual IInterceptorSelector for predicate-based configuration.
  9. Compare Castle Windsor and AspectCore + MSDI registration

    master

    When moving from Castle Windsor to AspectCore with Microsoft.Extensions.DependencyInjection (MSDI), the registration patterns change from component-based to service-collection-based.

    AspectCastle WindsorAspectCore + MSDI
    ContainerWindsorContainerIServiceCollection + IServiceProvider
    RegistrationComponent.For<>().ImplementedBy<>()services.AddTransient<,>()
    Interceptor bindingInterceptors(InterceptorReference...)config.Interceptors.AddTyped<>()
    Resolutioncontainer.Resolve<T>()serviceProvider.GetRequiredService<T>()
    Disposalcontainer.Dispose()serviceProvider.Dispose() (if ServiceProvider)
  10. Intercept IAsyncEnumerable<T> and IAsyncDisposable

    master

    AspectCore supports asynchronous streams and asynchronous disposal through its proxy engines.

    • IAsyncEnumerable<T>: The interceptor chain executes when the caller first enumerates the stream. The AspectContext is automatically released in the iterator's finally block, ensuring cleanup regardless of whether the stream completes normally, is cancelled, or encounters an exception.
    • IAsyncDisposable: The DisposeAsync() method is intercepted using the existing ValueTask return path.
  11. Understand AspectCore's module and layering architecture

    master

    AspectCore is organized into layers following unidirectional dependencies: contracts at the bottom, implementation in the middle, and integration at the top.

    • Foundation Layer: Contains AspectCore.Abstractions (interfaces and contracts) and AspectCore.Extensions.Reflection (standalone high-performance reflection).
    • Runtime Core Layer: Contains AspectCore.Core (the DynamicProxy engine and IoC container) and AspectCore.SourceGenerator (the compile-time engine).
    • Integration Layer: Contains DI adapters (e.g., Extensions.Autofac, Extensions.DependencyInjection) that weave AspectCore into specific dependency injection containers.
    • Feature/Extension Layer: Contains specialized features like Extensions.AspNetCore or Extensions.DataAnnotations.

    This structure ensures that core logic remains decoupled from specific DI containers or high-level frameworks.

  12. Compare Positive Matching and Negative Exclusion

    master

    AspectCore provides two distinct ways to control interception. You can stack them: use predicates to define the broad scope of what should be intercepted, and use exclusion mechanisms to define what should not be intercepted.

    | Mechanism | Effect | Where it is used |
    |------|------|------|
    | `Predicates.*` | Constrains which methods a global interceptor **matches** | Passed as `AspectPredicate[]` when registering an interceptor |
    | `[NonAspect]` | Precisely excludes a specific type/method from **being proxied** | Applied to an interface/class/method |
    | `NonAspectPredicates.*` | **Excludes proxying** in bulk by namespace/service/method | In `IAspectConfiguration` configuration |