Rougamo.Fody
4.0.1
See the version list below for details.
dotnet add package Rougamo.Fody --version 4.0.1
NuGet\Install-Package Rougamo.Fody -Version 4.0.1
<PackageReference Include="Rougamo.Fody" Version="4.0.1" />
paket add Rougamo.Fody --version 4.0.1
#r "nuget: Rougamo.Fody, 4.0.1"
// Install Rougamo.Fody as a Cake Addin #addin nuget:?package=Rougamo.Fody&version=4.0.1 // Install Rougamo.Fody as a Cake Tool #tool nuget:?package=Rougamo.Fody&version=4.0.1
Rougamo - 肉夹馍
中文 | English
What is Rougamo
Rougamo is a static code weaving AOP component. Commonly used AOP components include Castle, Autofac, and AspectCore. Unlike these components, which typically implement AOP through dynamic proxy and IoC mechanisms at runtime, Rougamo achieves AOP by directly modifying the target method's IL code during compilation. Rougamo supports all types of methods, including synchronous/asynchronous methods, static/instance methods, constructors, and properties.
The origin of the name.
Rougamo, a type of traditional Chinese street food, is somewhat similar to a hamburger, as both involve meat being sandwiched between bread. Every time I mention AOP, I think of Rougamo, because AOP is just like Rougamo, do aspects around the mehod.
Rougamo's Advantages and Disadvantages
Advantages:
- Shorter Application Startup Time: Static weaving occurs at compile time, whereas dynamic proxies are set up at application startup.
- Support for All Methods: Rougamo supports all methods, including constructors, properties, and static methods. Dynamic proxies often only handle instance methods due to their reliance on IoC.
- Independent from Other Components: Rougamo does not require initialization and is easy and quick to use. Dynamic AOP relies on IoC components, which often need initialization at application startup and vary between different IoC components. Rougamo does not require initialization; you just define the aspect type and apply it.
Disadvantages:
- Larger Assembly Size: Since Rougamo is a compile-time AOP, it weaves additional code into the assembly at compile time, which increases the assembly size. However, this overhead is generally minimal and can be evaluated in your project through configuration options.
- Less Convenient IoC Interaction: Dynamic AOP can easily access the IoC container and inject types into aspect types due to its reliance on IoC. Rougamo, being a compile-time AOP, does not depend on IoC components and thus cannot directly interact with IoC through methods like constructor injection. However, it can still be used with IoC; see using IoC in Rougamo for details.
Basic Functionality Introduction
As an AOP component, Rougamo's primary function is to execute additional operations at key lifecycle points of a method. Rougamo supports four lifecycle points (or Join Points):
- Before method execution;
- After method execution successfully;
- After method throws an exception;
- When the method exits (regardless of whether it was successful or threw an exception, similar to
try..finally
).
Here's a simple example demonstrating how lifecycle points are expressed in code:
// Define a type inheriting from MoAttribute
public class TestAttribute : MoAttribute
{
public override void OnEntry(MethodContext context)
{
// OnEntry corresponds to before method execution
}
public override void OnException(MethodContext context)
{
// OnException corresponds to after method throws an exception
}
public override void OnSuccess(MethodContext context)
{
// OnSuccess corresponds to after method execution successfully
}
public override void OnExit(MethodContext context)
{
// OnExit corresponds to when method exits
}
}
At each lifecycle point, in addition to performing operations like logging, measuring method execution time, and APM instrumentation that don't affect method execution, you can also:
- Modify method parameters
- Intercept method execution
- Modify method return values
- Handle method exceptions
- Retry method execution
Applying Rougamo to Methods
The simplest and most direct way is to apply the defined Attribute
directly to methods. This can include synchronous and asynchronous methods, instance methods and static methods, properties and property getters/setters, as well as instance and static constructors:
class Abc
{
[Test]
static Abc() { }
[Test]
public Abc() { }
[Test]
public int X { get; set; }
public static Y
{
[Test]
get;
[Test]
set;
}
[Test]
public void M() { }
[Test]
public static async ValueTask MAsync() => await Task.Yield();
}
Applying attributes directly to methods is straightforward, but for common AOP types, adding the attribute to every method can be cumbersome. Rougamo also provides several bulk application methods:
- Class or assembly-level attributes
- Low-intrusive implementation of the empty interface IRougamo
- Specify an attribute as a proxy attribute and apply it to methods with the proxy attribute
When applying attributes in bulk, such as applying TestAttribute
to a class, you typically don’t want every method in the class to receive TestAttribute
. Instead, you may want to select methods that meet specific criteria. Rougamo offers two methods for method selection:
- Coarse-grained method feature matching, which allows specifying static, instance, public, private, property, constructor methods, etc.
- AspectJ-style class expressions, which provide AspectJ-like expressions for finer-grained matching, such as method names, return types, parameter types, etc.
Asynchronous Aspects
In modern development, asynchronous programming has become quite common. In the previous example, the method lifecycle nodes correspond to synchronous methods. If you need to perform asynchronous operations, you would have to manually block asynchronous operations to wait for the results, which can lead to resource wastage and performance loss. Rougamo provides asynchronous aspects in addition to synchronous aspects to better support asynchronous operations:
// Define a type that inherits from AsyncMoAttribute
public class TestAttribute : AsyncMoAttribute
{
public override async ValueTask OnEntryAsync(MethodContext context) { }
public override async ValueTask OnExceptionAsync(MethodContext context) { }
public override async ValueTask OnSuccessAsync(MethodContext context) { }
public override async ValueTask OnExitAsync(MethodContext context) { }
}
However, if asynchronous operations are not needed, it's still recommended to use synchronous aspects. For more information on asynchronous aspects, you can refer to Asynchronous Aspects.
Performance Optimization
Rougamo is a method-level AOP component. When applying Rougamo to methods, it instantiates related objects each time the method is called, which adds a burden to garbage collection (GC). Although this overhead is usually minimal and often negligible, Rougamo addresses performance impact by providing various optimization strategies:
Partial Weaving: If you only want to record a call log before method execution and do not need other lifecycle nodes or exception handling, you can use partial weaving to include only the required functionalities. This reduces the actual IL code woven and minimizes the number of instructions executed at runtime.
Structs: One difference between classes and structs is that classes are allocated on the heap, while structs are allocated on the stack. Using structs can allocate some Rougamo types on the stack, reducing GC pressure.
Slimming MethodContext:
MethodContext
holds contextual information about the current method. This information requires additional objects and involves boxing and unboxing operations, such as for method parameters and return values. If you do not need this information, slimming downMethodContext
can achieve certain optimization effects.Forced Synchronization: As discussed in Asynchronous Aspects, asynchronous aspects use
ValueTask
to optimize synchronous execution but still incur additional overhead. If asynchronous operations are not required, forcing synchronous aspects can avoid the extra costs of asynchronous aspects.
Learn More
- Configuration Options
- Using IoC in Rougamo
- Special Note on async void
- Custom Execution Order When Using Multiple Rougamo Types
- Specifying Rougamo Built-in Attributes When Using Attributes
- Special Parameters or Return Value Types (ref struct)
- Considerations for Developing Middleware with Rougamo
- Overview of Functional Support for Different Method Types
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Fody (>= 6.8.1)
- System.Threading.Tasks.Extensions (>= 4.5.4)
NuGet packages (43)
Showing the top 5 NuGet packages that depend on Rougamo.Fody:
Package | Downloads |
---|---|
HandeSoft.Core
Package Description |
|
HandeSoft.Web.Core
Package Description |
|
BotSharp.Abstraction
Package Description |
|
Ray.Infrastructure
This client library is a infrastructure that including extensions and helpers etc. |
|
HZY.Framework.Core
HZY Framework 核心 1、ScheduledAttribute 定时任务特性标记 2、IServerMetricMonitoringService 服务器指标监控 CPU、内存、硬盘、运行时长 3、HZY.Framework.DynamicApiController 动态Api控制器 4、HZY.Framework.DependencyInjection 依赖注入 |
GitHub repositories (5)
Showing the top 5 popular GitHub repositories that depend on Rougamo.Fody:
Repository | Stars |
---|---|
RayWangQvQ/BiliBiliToolPro
B 站(bilibili)自动任务工具,支持docker、青龙、k8s等多种部署方式。敏感肌也能用。
|
|
dotnetcore/FreeSql
🦄 .NET aot orm, C# orm, VB.NET orm, Mysql orm, Postgresql orm, SqlServer orm, Oracle orm, Sqlite orm, Firebird orm, 达梦 orm, 人大金仓 orm, 神通 orm, 翰高 orm, 南大通用 orm, 虚谷 orm, 国产 orm, Clickhouse orm, DuckDB orm, TDengine orm, QuestDB orm, MsAccess orm.
|
|
SciSharp/BotSharp
AI Multi-Agent Framework in .NET
|
|
2881099/FreeSql.AdminLTE
这是一个 .NETCore MVC 中间件,基于 AdminLTE 前端框架动态产生 FreeSql 实体的增删查改界面。
|
|
ThingsGateway/ThingsGateway
ThingsGateway is a cross platform high-performance edge acquisition gateway based on Net8, providing underlying PLC communication libraries, communication debugging software, and more.
|
Version | Downloads | Last updated | |
---|---|---|---|
4.0.4 | 2,457 | 9/29/2024 | |
4.0.4-preview-1727349912 | 92 | 9/26/2024 | |
4.0.3 | 1,225 | 9/16/2024 | |
4.0.3-preview-1726120802 | 96 | 9/12/2024 | |
4.0.3-preview-1725957423 | 104 | 9/10/2024 | |
4.0.2 | 504 | 9/9/2024 | |
4.0.2-preview-1725956948 | 95 | 9/10/2024 | |
4.0.2-preview-1725875652 | 94 | 9/9/2024 | |
4.0.2-preview-1725466232 | 96 | 9/4/2024 | |
4.0.1 | 2,622 | 9/2/2024 | |
4.0.1-preview-1725141430 | 88 | 8/31/2024 | |
4.0.0 | 6,041 | 8/10/2024 | |
4.0.0-priview-1723306347 | 109 | 8/10/2024 | |
4.0.0-priview-1722831925 | 86 | 8/5/2024 | |
3.1.0 | 1,501 | 7/16/2024 | |
3.0.2 | 437 | 7/8/2024 | |
3.0.2-priview-1720363148 | 103 | 7/7/2024 | |
3.0.2-priview-1720251661 | 101 | 7/6/2024 | |
3.0.1 | 185 | 7/4/2024 | |
3.0.1-priview-1720089186 | 106 | 7/4/2024 | |
3.0.1-priview-1720085112 | 89 | 7/4/2024 | |
3.0.0 | 3,392 | 5/4/2024 | |
3.0.0-priview-1714754497 | 78 | 5/3/2024 | |
3.0.0-priview-1714407561 | 131 | 4/29/2024 | |
2.3.1 | 7,372 | 4/23/2024 | |
2.3.1-priview-1713854631 | 114 | 4/23/2024 | |
2.3.1-priview-1713791514 | 102 | 4/22/2024 | |
2.3.0 | 3,775 | 3/10/2024 | |
2.3.0-priview-1709894403 | 113 | 3/8/2024 | |
2.2.0 | 2,949 | 1/20/2024 | |
2.2.0-priview-1705656978 | 109 | 1/19/2024 | |
2.2.0-priview-1705571301 | 103 | 1/18/2024 | |
2.2.0-priview-1705566213 | 109 | 1/18/2024 | |
2.2.0-priview-1702899195 | 184 | 12/18/2023 | |
2.1.1 | 4,611 | 12/14/2023 | |
2.1.1-priview-1702545048 | 142 | 12/14/2023 | |
2.1.1-priview-1702542781 | 140 | 12/14/2023 | |
2.0.1 | 1,246 | 11/16/2023 | |
2.0.0 | 2,985 | 10/8/2023 | |
2.0.0-priview-1696783135 | 135 | 10/8/2023 | |
2.0.0-priview-1696592398 | 130 | 10/6/2023 | |
2.0.0-priview-1695658688 | 156 | 9/25/2023 | |
2.0.0-priview-1695465141 | 149 | 9/23/2023 | |
2.0.0-priview-1680984436 | 221 | 4/8/2023 | |
2.0.0-priview-1680981587 | 181 | 4/8/2023 | |
1.4.1 | 11,396 | 3/12/2023 | |
1.4.1-priview-1678603084 | 188 | 3/12/2023 | |
1.4.1-priview-1678557697 | 189 | 3/11/2023 | |
1.4.1-priview-1678557463 | 187 | 3/11/2023 | |
1.4.0 | 2,648 | 3/1/2023 | |
1.4.0-beta | 362 | 2/27/2023 | |
1.4.0-alpha | 234 | 2/25/2023 | |
1.3.4 | 56,776 | 2/17/2023 | |
1.3.3 | 978 | 1/17/2023 | |
1.3.2 | 18,297 | 12/20/2022 | |
1.3.1 | 341 | 12/20/2022 | |
1.3.1-beta | 178 | 12/14/2022 | |
1.3.0 | 1,281 | 12/8/2022 | |
1.2.3 | 347 | 1/17/2023 | |
1.2.2 | 320 | 12/20/2022 | |
1.2.2-beta | 168 | 12/14/2022 | |
1.2.1 | 695 | 11/29/2022 | |
1.2.1-beta | 163 | 11/29/2022 | |
1.2.0 | 2,061 | 9/14/2022 | |
1.2.0-beta | 183 | 9/12/2022 | |
1.2.0-alpha2 | 173 | 9/12/2022 | |
1.2.0-alpha1 | 180 | 8/31/2022 | |
1.2.0-alpha | 173 | 8/30/2022 | |
1.1.4 | 373 | 11/29/2022 | |
1.1.4-alpha | 189 | 12/25/2022 | |
1.1.3 | 532 | 9/11/2022 | |
1.1.2 | 1,647 | 8/22/2022 | |
1.1.2-beta | 180 | 8/22/2022 | |
1.1.1 | 2,807 | 8/8/2022 | |
1.1.1-beta | 190 | 8/1/2022 | |
1.1.0 | 630 | 7/28/2022 | |
1.1.0-beta | 205 | 7/15/2022 | |
1.1.0-alpha4 | 188 | 6/24/2022 | |
1.1.0-alpha3 | 175 | 6/24/2022 | |
1.1.0-alpha2 | 174 | 6/23/2022 | |
1.1.0-alpha1 | 176 | 6/22/2022 | |
1.1.0-alpha | 190 | 5/22/2022 | |
1.0.3 | 712 | 5/6/2022 | |
1.0.3-beta | 195 | 4/26/2022 | |
1.0.2 | 696 | 12/23/2021 | |
1.0.1 | 7,736 | 11/23/2021 | |
1.0.1-beta | 4,919 | 11/23/2021 |
- 修复 [[#77](https://github.com/inversionhourglass/Rougamo/issues/77)]
### 修复描述
异步方法的调试信息不仅需要对应的DebugInformation和CustomDebugInformation以及一些Attribute,生成的StateMachine类名以及变量对应的字段名也有一定格式要求,具体参考:
- 类名生成:https://github.com/dotnet/roslyn/blob/5cba0ce666766b1db7cd75009575c7e12c4be72c/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs#L78-L84
- 字段名生成:https://github.com/dotnet/roslyn/blob/5cba0ce666766b1db7cd75009575c7e12c4be72c/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs#L203-L244
- 字段solt计算:https://github.com/dotnet/roslyn/blob/5cba0ce666766b1db7cd75009575c7e12c4be72c/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs#L194-L197
---