Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AGENTS.md — AspectCore-Framework

Project-level AI context for the AspectCore-Framework repository. Generated from the current code tree (commit `d7750bf`, version `2.7.0`). Keep this file lean; link to external docs instead of inlining them.
Project-level AI context for the AspectCore-Framework repository. Generated from the current code tree (version `3.0.0-rc.1`). Keep this file lean; link to external docs instead of inlining them.

---

Expand All @@ -12,14 +12,14 @@ Project-level AI context for the AspectCore-Framework repository. Generated from
- **Source Generator** (compile-time, Roslyn `IIncrementalGenerator`) — lives in `AspectCore.SourceGenerator`.

**Tech stack (concrete):**
- **.NET target frameworks (libraries):** `net9.0;net8.0;net7.0;net6.0;netstandard2.1;netstandard2.0` (AspNetCore drops netstandard; SourceGenerator is `netstandard2.0` only).
- **.NET target frameworks (libraries):** `net10.0;net9.0;net8.0;net6.0` (SourceGenerator is `netstandard2.0` only, as required by Roslyn).
- **.NET target frameworks (tests):** `net10.0;net9.0;net8.0;net6.0`.
- **C# language version:** `10.0` for `src/` (set in `build/common.props`); `13.0` for tests.
- **C# language version:** `13.0` for `src/` (set in `build/common.props`); `13.0` for tests.
- **Test framework:** xUnit `2.9.2` + `Microsoft.NET.Test.Sdk 17.12.0`.
- **Coverage:** `coverlet.msbuild 6.0.2` (Cobertura), thresholds enforced in CI (unit 95%, E2E 80%).
- **DI integrations:** MsDI, Autofac `[7.0.0, 8.0.0)`, Castle.Windsor `6.0.0`, LightInject `6.6.4`, plus Generic Host and ASP.NET Core adapters.
- **Benchmarks:** BenchmarkDotNet `0.14.0`.
- **Version source of truth:** `build/version.props` (`VersionMajor=2`, `VersionMinor=7`, `VersionPatch=0`).
- **Version source of truth:** `build/version.props` (`VersionMajor=3`, `VersionMinor=0`, `VersionPatch=0`, `VersionQuality=rc.1`).

---

Expand All @@ -41,7 +41,8 @@ Project-level AI context for the AspectCore-Framework repository. Generated from
| `src/AspectCore.Extensions.Configuration/` | Configuration injection via `Microsoft.Extensions.Configuration`. | – |
| `src/AspectCore.Extensions.DataAnnotations/` | DataAnnotations-based validation extension. | – |
| `src/AspectCore.Extensions.DataValidation/` | Data validation extension. | – |
| `tests/` | 9 xUnit test projects. `tests/Directory.Build.props` injects `coverlet.msbuild`. | – |
| `src/AspectCore.Extensions.CastleCompat/` | Castle DynamicProxy compatibility shim for gradual migration to AspectCore. Depends on `Castle.Core`. Targets `net10.0;net9.0;net8.0`. | – |
| `tests/` | 10 xUnit test projects + `AspectCore.NativeAot.E2E` (a `PublishAot` executable, not xUnit). `tests/Directory.Build.props` injects `coverlet.msbuild`. | – |
| `sample/` | 4 runnable sample projects (DI console, AspectScope, Autofac, DataAnnotations). | – |
| `benchmark/` `benchmarks/` | BenchmarkDotNet projects. | – |
| `docs/` | Architecture, guide, getting-started, development, testing docs (bilingual; `docs/en/` for English). | `docs/README.md` |
Expand All @@ -67,7 +68,7 @@ for project in $(find ./src -name "*.csproj"); do
done

# Build with explicit version (CI release flow)
dotnet build --configuration Release ./src/AspectCore.Core/AspectCore.Core.csproj -p:Version=2.7.0
dotnet build --configuration Release ./src/AspectCore.Core/AspectCore.Core.csproj -p:Version=3.0.0-rc.1

# Format check (PR CI gate — currently warns, does not fail)
dotnet format AspectCore-Framework.sln --verify-no-changes
Expand All @@ -81,13 +82,13 @@ dotnet format AspectCore-Framework.sln
# Pack all src projects (CI build flow, includes source/symbols)
for project in $(find ./src -name "*.csproj"); do
dotnet pack --configuration Release --no-build "$project" \
-p:PackageVersion=2.7.0 --include-source --output ./artifacts/packages
-p:PackageVersion=3.0.0-rc.1 --include-source --output ./artifacts/packages
done

# Pack single project
dotnet pack --configuration Release --no-build \
./src/AspectCore.Core/AspectCore.Core.csproj \
-p:PackageVersion=2.7.0 --output ./artifacts/packages
-p:PackageVersion=3.0.0-rc.1 --output ./artifacts/packages
```

**Run a sample:**
Expand Down Expand Up @@ -150,7 +151,7 @@ dotnet test ./tests/AspectCore.Core.Tests/AspectCore.Core.Tests.csproj \

## 6. Code Style Guidelines

Formatting is enforced by `dotnet format` (no `.editorconfig`; uses .NET SDK defaults). `src/Directory.Build.props` enables .NET analyzers at informational level (non-blocking). `LangVersion=10.0` for `src/`.
Formatting is enforced by `dotnet format` (no `.editorconfig`; uses .NET SDK defaults). `src/Directory.Build.props` enables .NET analyzers at informational level (non-blocking). `LangVersion=13.0` for `src/`.

**Namespaces — block-scoped, not file-scoped:**
```csharp
Expand Down Expand Up @@ -206,6 +207,7 @@ public async Task Invoke(AspectContext context, AspectDelegate next)
- ✅ **Always do** — run `dotnet format` locally before pushing to avoid the CI lint gate.
- ✅ **Always do** — put new public interfaces/attributes in `AspectCore.Abstractions`; implementations in `Core` or the relevant extension.
- ✅ **Always do** — use Conventional Commits and the fixed committer identity (`Haoyang Liu`).
- ✅ **Always do** — after changing code functionality, check whether `AGENTS.md`, `README`, `ROADMAP`, and `docs/` have drifted from the new behavior; if so, update the affected docs in the same change so documentation stays in sync with the code.
- ⚠️ **Ask first** — bumping `build/version.props` (release flow auto-bumps minor only; patch bumps need explicit approval).
- ⚠️ **Ask first** — changing target frameworks or `LangVersion` in `build/common.props` (affects all packages and CI matrix).
- ⚠️ **Ask first** — adding a new DI container integration or a new top-level package.
Expand Down
30 changes: 30 additions & 0 deletions AspectCore-Framework.sln
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspectCore.NativeAot.E2E", "tests\AspectCore.NativeAot.E2E\AspectCore.NativeAot.E2E.csproj", "{A8E6B15A-6F34-44C7-B60F-FA8CD44D2FCC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspectCore.Extensions.CastleCompat", "src\AspectCore.Extensions.CastleCompat\AspectCore.Extensions.CastleCompat.csproj", "{2E607FEC-D838-4F9B-9649-F892CAE4C607}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspectCore.Extensions.CastleCompat.Tests", "tests\AspectCore.Extensions.CastleCompat.Tests\AspectCore.Extensions.CastleCompat.Tests.csproj", "{3B771AA2-C30A-415E-A4E8-D7FAA215A653}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -459,6 +463,30 @@ Global
{A8E6B15A-6F34-44C7-B60F-FA8CD44D2FCC}.Release|x64.Build.0 = Release|Any CPU
{A8E6B15A-6F34-44C7-B60F-FA8CD44D2FCC}.Release|x86.ActiveCfg = Release|Any CPU
{A8E6B15A-6F34-44C7-B60F-FA8CD44D2FCC}.Release|x86.Build.0 = Release|Any CPU
{2E607FEC-D838-4F9B-9649-F892CAE4C607}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E607FEC-D838-4F9B-9649-F892CAE4C607}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E607FEC-D838-4F9B-9649-F892CAE4C607}.Debug|x64.ActiveCfg = Debug|Any CPU
{2E607FEC-D838-4F9B-9649-F892CAE4C607}.Debug|x64.Build.0 = Debug|Any CPU
{2E607FEC-D838-4F9B-9649-F892CAE4C607}.Debug|x86.ActiveCfg = Debug|Any CPU
{2E607FEC-D838-4F9B-9649-F892CAE4C607}.Debug|x86.Build.0 = Debug|Any CPU
{2E607FEC-D838-4F9B-9649-F892CAE4C607}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E607FEC-D838-4F9B-9649-F892CAE4C607}.Release|Any CPU.Build.0 = Release|Any CPU
{2E607FEC-D838-4F9B-9649-F892CAE4C607}.Release|x64.ActiveCfg = Release|Any CPU
{2E607FEC-D838-4F9B-9649-F892CAE4C607}.Release|x64.Build.0 = Release|Any CPU
{2E607FEC-D838-4F9B-9649-F892CAE4C607}.Release|x86.ActiveCfg = Release|Any CPU
{2E607FEC-D838-4F9B-9649-F892CAE4C607}.Release|x86.Build.0 = Release|Any CPU
{3B771AA2-C30A-415E-A4E8-D7FAA215A653}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B771AA2-C30A-415E-A4E8-D7FAA215A653}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B771AA2-C30A-415E-A4E8-D7FAA215A653}.Debug|x64.ActiveCfg = Debug|Any CPU
{3B771AA2-C30A-415E-A4E8-D7FAA215A653}.Debug|x64.Build.0 = Debug|Any CPU
{3B771AA2-C30A-415E-A4E8-D7FAA215A653}.Debug|x86.ActiveCfg = Debug|Any CPU
{3B771AA2-C30A-415E-A4E8-D7FAA215A653}.Debug|x86.Build.0 = Debug|Any CPU
{3B771AA2-C30A-415E-A4E8-D7FAA215A653}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B771AA2-C30A-415E-A4E8-D7FAA215A653}.Release|Any CPU.Build.0 = Release|Any CPU
{3B771AA2-C30A-415E-A4E8-D7FAA215A653}.Release|x64.ActiveCfg = Release|Any CPU
{3B771AA2-C30A-415E-A4E8-D7FAA215A653}.Release|x64.Build.0 = Release|Any CPU
{3B771AA2-C30A-415E-A4E8-D7FAA215A653}.Release|x86.ActiveCfg = Release|Any CPU
{3B771AA2-C30A-415E-A4E8-D7FAA215A653}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -497,6 +525,8 @@ Global
{D7C79A32-0351-4E4A-B851-66D52C29CBF1} = {66320409-64EC-F7C5-3DEF-65E7510DAAD1}
{72FACDC8-250C-444B-A4C1-F86EDC2B16E1} = {2DFB45E4-F9D9-472C-93E4-224E3C210FCB}
{A8E6B15A-6F34-44C7-B60F-FA8CD44D2FCC} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
{2E607FEC-D838-4F9B-9649-F892CAE4C607} = {01E9B5AA-9C01-458A-ADF5-8D66101F2FB8}
{3B771AA2-C30A-415E-A4E8-D7FAA215A653} = {2DFB45E4-F9D9-472C-93E4-224E3C210FCB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {71EABBEC-431F-413C-B6CB-CFE9145BCAD4}
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[![Build](https://github.com/dotnetcore/AspectCore-Framework/actions/workflows/build-ci.yml/badge.svg)](https://github.com/dotnetcore/AspectCore-Framework/actions/workflows/build-ci.yml)
[![Member project of .NET Core Community](https://img.shields.io/badge/member%20project%20of-NCC-9e20c9.svg)](https://github.com/dotnetcore)
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/dotnetcore/AspectCore/blob/dev/LICENSE)
AspectCore is an Aspect-Oriented Programming based cross platform framework for .NET Core and .NET Framework.
AspectCore is an Aspect-Oriented Programming based cross platform framework for .NET 6+.

Core support for aspect-interceptor, dependency injection integration, web applications, data validation, and more.

Expand Down
37 changes: 32 additions & 5 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,20 +139,47 @@ AspectCore 不再把增长重点放在“更大的 IoC 容器”或“更复杂

| 风险 | 等级 | 说明 | 缓解策略 |
|------|------|------|----------|
| **NativeAOT 过时风险** | 最高 | 若 12–18 个月内无法提供端到端 NativeAOT 支持,将与平台方向不兼容 | P0-3 为最高优先级;在 NativeAOT 路径上彻底移除 `DynamicMethod`;建立 NativeAOT CI 门禁 |
| NativeAOT 体验不可信 | 最高 | 只要用户遇到运行时崩溃或不可解释的 publish failure,就很难相信 Source Generator 路径 | 把失败前移到 `ACSGxxx` 诊断;NativeAOT E2E 必须 publish + run;明确 DynamicProxy 非 AOT |
| **Metalama 免费层扩张** | 高 | Metalama 若扩大免费层功能,将侵蚀 AspectCore"免费 + 开源"的差异化优势 | 强化开源社区治理、双引擎一致性、与 MSDI 深度集成等 Metalama 不具备的优势;保持完全开源 |
| 迁移成本过高 | 高 | Castle/Windsor 用户不是因为框架名迁移,而是因为 AOT、性能和现代 C# 需求迁移 | analyzer/CLI 输出迁移报告;保留兼容垫片;提供 before/after sample |
| **Castle Source Generator 发布** | 中 | Castle v6.0 若发布 Source Generator,将缩小 AspectCore 在编译时方向的差距 | 加快 P0-3(NativeAOT)落地,强化双引擎一致性与现代 C# 特性适配,在 Castle 之前占据 NativeAOT 的生态位 |
| **社区可持续性** | 中 | 团队规模小,节奏激进,存在 burnout 风险 | 建立贡献者指南与自动化 CI/CD 降低维护成本;优先保障 P0 事项,P1 事项可吸纳社区贡献;避免在非核心方向过度消耗 |
| **Keyed 服务缺口损害信任** | 中 | `NotImplementedException` 被作为"预期行为"测试,传递出"功能不完整"的负面信号 | P0-1 + P0-2 立即修复;修复后发布公告,主动恢复用户信心 |
| 横切包范围失控 | 中 | 官方包过多会变成维护负担,并把项目拖向应用框架 | 第一批只做基础设施包;复用成熟生态;高风险语义延后 |
| benchmark 不可复现 | 中 | 宣传性能但无可复现结果会损害信任 | BenchmarkDotNet 工程、环境说明、结果归档、CI 编译门禁 |

---

## 五、决策原则

1. **平台方向优先**:NativeAOT / trimming / Source Generator 是主线。
2. **迁移价值优先**:优先承接已有 Castle/Windsor 用户的真实迁移成本。
3. **生态复用优先**:OpenTelemetry、Polly、Microsoft.Extensions.* 这类成熟标准优先,不自造协议。
4. **可诊断优先**:无法支持的场景必须有清晰诊断、文档和替代路径。
5. **兼容优先**:默认运行时行为不轻易改变;Source Generator / NativeAOT 以显式 opt-in 和 `Strict` 模式推进。
| 阶段 | 时间窗口 | 事项 | 优先级 |
|------|----------|------|--------|
| **短期** | 第 1–2 周 | P0-1:修复 keyed 服务解析缺口 | P0 |
| | | P0-2:keyed 服务拦截集成测试 | P0 |
| **中期** | 第 1–3 个月 | P0-3:端到端 NativeAOT 支持 | P0 |
| | | P1-2:Windsor 迁移指南与工具 | P1 |
| | | P1-3:对标竞品基准测试套件 | P1 |
| **长期** | 第 3–12 个月 | 持续跟进 C# 最新特性适配 | P2 |
| | | 扩展生态集成(更多 DI 容器、框架) | P2 |
| | | 社区治理与贡献者体系建设 | P2 |

> **优先级说明**:P0 = 必须立即完成,阻塞核心竞争力或损害用户信任;P1 = 应在中期内完成,强化差异化优势;P2 = 长期投入,视社区资源与市场反馈动态调整。

---

## 六、优先级决策原则

当资源有限时,按以下顺序取舍:

1. **用户信任优先**:已暴露的功能缺口(如 keyed 服务)必须先于新特性修复。
2. **平台方向优先**:NativeAOT / trimming / Source Generator 是主线;NativeAOT 是 .NET 平台的确定性方向,与之兼容是生存前提。
3. **迁移价值优先**:优先承接已有 Castle/Windsor 用户的真实迁移成本。
4. **差异化优先**:选择能放大 AspectCore 独特优势(双引擎一致性、现代 C# 适配、开源免费)的投入。
5. **生态复用优先**:OpenTelemetry、Polly、Microsoft.Extensions.* 这类成熟标准优先,不自造协议。
6. **可诊断优先**:无法支持的场景必须有清晰诊断、文档和替代路径。
7. **可验证优先**:每项工作必须有明确的验收标准与 CI 门禁,避免"完成了但无法证明"。
8. **兼容优先**:默认运行时行为不轻易改变;Source Generator / NativeAOT 以显式 opt-in 和 `Strict` 模式推进。

---

Expand Down
10 changes: 8 additions & 2 deletions benchmarks/AspectCore.Benchmarks/AdditionalBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,14 @@ public override void Setup()
_sourceGenProxy = (LargeStructService)SourceGenProxyGen.CreateClassProxy(typeof(LargeStructService), typeof(LargeStructService), Array.Empty<object>());
_data = new LargeStruct
{
Field1 = 1, Field2 = 2, Field3 = 3, Field4 = 4,
Field5 = 5, Field6 = 6, Field7 = 7, Field8 = 8
Field1 = 1,
Field2 = 2,
Field3 = 3,
Field4 = 4,
Field5 = 5,
Field6 = 6,
Field7 = 7,
Field8 = 8
};
}

Expand Down
2 changes: 1 addition & 1 deletion build/version.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<VersionMajor>3</VersionMajor>
<VersionMinor>0</VersionMinor>
<VersionPatch>0</VersionPatch>
<VersionQuality>beta.1</VersionQuality>
<VersionQuality>rc.1</VersionQuality>
<VersionPrefix>$(VersionMajor).$(VersionMinor).$(VersionPatch)</VersionPrefix>
<VersionSuffix Condition="'$(VersionQuality)' != ''">$(VersionQuality)</VersionSuffix>
</PropertyGroup>
Expand Down
4 changes: 2 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AspectCore 文档

> AspectCore 是面向 .NET Core 与 .NET Framework 的跨平台 AOP(面向切面编程)框架,提供动态代理拦截、依赖注入集成、Web 应用支持、数据校验等能力。
> AspectCore 是面向 .NET 6+ 的跨平台 AOP(面向切面编程)框架,提供动态代理拦截、依赖注入集成、Web 应用支持、数据校验等能力。

本目录是 AspectCore 的完整文档。中文为主,英文版本见 [`en/`](./en/README.md)(English documentation lives under [`en/`](./en/README.md))。

Expand Down Expand Up @@ -31,7 +31,7 @@
面向贡献者与深度使用者的设计文档。

- [总体架构](./architecture/overview.md) — 分层与运行流程
- [模块与包结构设计](./architecture/module-design.md) — 14 个包的职责边界与依赖方向
- [模块与包结构设计](./architecture/module-design.md) — 15 个包的职责边界与依赖方向
- [DynamicProxy 运行时引擎](./architecture/dynamic-proxy.md) — 基于 Reflection.Emit 的运行时代理
- [Source Generator 编译时引擎](./architecture/source-generator.md) — 基于 Roslyn 的编译时代理
Comment thread
latte-gh marked this conversation as resolved.
Comment thread
latte-gh marked this conversation as resolved.
Comment thread
latte-gh marked this conversation as resolved.
Comment thread
latte-gh marked this conversation as resolved.
- [两套引擎对比与选型](./architecture/engine-comparison.md) — DynamicProxy vs SourceGenerator vs Auto
Expand Down
5 changes: 2 additions & 3 deletions docs/architecture/language-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ AspectCore 拥有两套 AOP 引擎:

当前状态:

- `LangVersion` 设为 `10.0`(核心库),Source Generator 使用 `latest`
- 支持 `net6.0` ~ `net9.0` + `netstandard2.0/2.1`
- `LangVersion` 设为 `13.0`(核心库),Source Generator 使用 `latest`
- 支持 `net6.0` ~ `net10.0`(`AspectCore.SourceGenerator` 为 `netstandard2.0`)
- 两套引擎在方法体生成上有不同路径:DynamicProxy 通过 `ReturnKind` 枚举分发到 `AspectActivator.Invoke*` 系列方法;Source Generator 根据同步/异步生成不同的内联代码

### 1.1 AOP Emit 核心流程
Expand Down Expand Up @@ -70,7 +70,6 @@ AspectCore 拥有两套 AOP 引擎:
- `ReturnKind` 新增 `AsyncEnumerable`;DynamicProxy 和 Source Generator 分别调用 `IAspectActivator.InvokeAsyncEnumerable<T>`。
- 异步流保持惰性:拦截器链和目标方法在首次枚举时执行;流完成、取消或枚举期间发生异常时,`AspectContext` 都会释放。
- `IAsyncDisposable.DisposeAsync()` 返回 `ValueTask`,已通过既有 `ValueTask` 代理路径完成拦截。
- `netstandard2.0` 目标引入 `Microsoft.Bcl.AsyncInterfaces`,以公开 C# 8 异步接口。

**验证覆盖**

Expand Down
Loading
Loading