Rougamo.Fody
1.2.0-beta
See the version list below for details.
dotnet add package Rougamo.Fody --version 1.2.0-beta
NuGet\Install-Package Rougamo.Fody -Version 1.2.0-beta
<PackageReference Include="Rougamo.Fody" Version="1.2.0-beta" />
paket add Rougamo.Fody --version 1.2.0-beta
#r "nuget: Rougamo.Fody, 1.2.0-beta"
// Install Rougamo.Fody as a Cake Addin #addin nuget:?package=Rougamo.Fody&version=1.2.0-beta&prerelease // Install Rougamo.Fody as a Cake Tool #tool nuget:?package=Rougamo.Fody&version=1.2.0-beta&prerelease
Rougamo - 肉夹馍
Translated by google
中文 | English
Rougamo, a Chinese snack, perhaps somewhat similar to a hamburger. Wrapping important logic code to provide AOP is like wrapping delicious stuffing in buns.
Quick start
// 1. Install-Package Rougamo.Fody
// 2. Define the class to inherit MoAttribute, and define the code that needs to be woven
public class LoggingAttribute : MoAttribute
{
public override void OnEntry(MethodContext context)
{
Log.Info("Before the method execution");
}
public override void OnException(MethodContext context)
{
Log.Error("When an exception occurs when the method is executed", context.Exception);
}
public override void OnSuccess(MethodContext context)
{
Log.Info("After the method executes successfully");
}
public override void OnExit(MethodContext context)
{
Log.Info("After the method is executed, whether it succeeds or fails");
}
}
// 3. Apply Attribute
public class Service
{
[Logging]
public static int Sync(Model model)
{
// ...
}
[Logging]
public async Task<Data> Async(int id)
{
// ...
}
}
Batch apply based on method accessibility
In the quick start, we introduced how to weave the code into the specified method, but in actual use, it may be very cumbersome and intrusive to add
this attribute to each method or many methods in a huge project, so MoAttribute
is designed to be applied to methods, classes, assemblies, and modules,
while setting accessibility attributes for added flexibility.
// 1. While inheriting MoAttribute, override the Flags attribute, and default to InstancePublic (public instance method) when not overridden.
public class LoggingAttribute : MoAttribute
{
// Changing to all public methods is valid, whether it is an instance method or a static method.
public override AccessFlags Flags => AccessFlags.Public;
// Method override omitted.
}
// 2. Apply
// 2.1. apply to class
[Logging]
public class Service
{
// Logging whill be apply.
public static void M1() { }
// Logging whill be apply.
public void M2() { }
// protected access level does not apply Logging code weaving.
protected void M3() { }
}
// 2.2. Applied to an assembly, all public methods of the assembly will be statically woven into the application.
[assembly: Logging]
Weaving by implementing an empty interface(IRougamo<>)
If marking each method via Attribute feels too cumbersome or intrusive, and batch weaving via method accessibility is too general and not custom enough, weaving via an empty interface will provide intrusiveness and convenient way.
// 1. Define the code that needs to be woven, or you can directly use the LoggingAttribute defined in the quick start.
public class LoggingMo : IMo
{
public override AccessFlags Flags => AccessFlags.All;
public override void OnEntry(MethodContext context)
{
// Information including input parameters, class instances, method descriptions, etc. can be obtained from the context object.
Log.Info("Before the method execution");
}
public override void OnException(MethodContext context)
{
Log.Error("When an exception occurs when the method is executed", context.Exception);
}
public override void OnExit(MethodContext context)
{
Log.Info("After the method is executed, whether it succeeds or fails");
}
public override void OnSuccess(MethodContext context)
{
Log.Info("After the method executes successfully");
}
}
// 2. Define an empty interface. The ILoggingRougamo interface defined in this step can be skipped, and IRougamo<LoggingMo> can also be implemented directly in the next step.
public interface ILoggingRougamo : IRougamo<LoggingMo>
{
}
// 3. Apply an empty interface. If you are used to defining a parent interface/parent class for the same type/domain class when programming, you only need the parent interface/parent class to implement the interface.
public interface IRepository<TModel, TId> : ILoggingRougamo
{
// ...
}
Exception handling and modifying return values(v1.1.0)
In the OnException
method, you can call the HandledException
method of MethodContext
to indicate that the exception has been handled and set the return value.
In the OnEntry
and OnSuccess
methods, you can modify the actual method by calling the ReplaceReturnValue
method of MethodContext
The return value of
ReturnValue
, ExceptionHandled
and other attributes should not be used to modify the return value and handle exceptions directly. HandledException
and
ReplaceReturnValue
contain some other logic, which may be updated in the future.
public class TestAttribute : MoAttribute
{
public override void OnException(MethodContext context)
{
// Handle exceptions and set the return value to newReturnValue. If the method has no return value (void), simply pass in null
context.HandledException(this, newReturnValue);
}
public override void OnSuccess(MethodContext context)
{
// Modify method return value
context.ReplaceReturnValue(this, newReturnValue);
}
}
Ignore weaving(IgnoreMoAttribute)
In the quick start, we introduced how to apply in batches. Since the rules of batch references only limit the accessibility of methods, there may be some methods that
meet the rules and do not want to apply weaving. At this time, you can use IgnoreMoAttribute
to specify method/ class, then that method/class (all methods) will
ignore weaving. If IgnoreMoAttribute
is applied to an assembly or module, all weaving will be ignored for that assembly/module. Additionally, it is possible to
specify ignored weaving types via MoTypes when applying the IgnoreMoAttribute
.
// The current assembly ignores all weaving
[assembly: IgnoreMo]
// The current assembly ignores weaving of TheMoAttribute
[assembly: IgnoreMo(MoTypes = new[] { typeof(TheMoAttribute))]
// The current class ignores all weaving
[IgnoreMo]
class Class1
{
// ...
}
// The current class ignores weaving of TheMoAttribute
[IgnoreMo(MoTypes = new[] { typeof(TheMoAttribute))]
class Class2
{
// ...
}
Attribute proxy weaving(MoProxyAttribute)
If you have used some third-party components to mark some methods with Attribute, and now you want to perform aop operations on these marked methods, but do not want to
manually add the Attribute mark of rougamo one by one, you can step by proxy. Complete aop weaving. Another example is that your project now has a lot of obsolete methods
marked with ObsoleteAttribute
. You want to output the call stack log when the expired method is called, to check which entries are using these expired methods. You can
also do this in this way.
public class ObsoleteProxyMoAttribute : MoAttribute
{
public override void OnEntry(MethodContext context)
{
Log.Warning("expired method was called." + Environment.StackTrace);
}
}
[module: MoProxy(typeof(ObsoleteAttribute), typeof(ObsoleteProxyMoAttribute))]
public class Cls
{
[Obsolete]
private int GetId()
{
// This method weaves the application into the code
return 123;
}
}
Weave Mutex
Single type mutex(IRougamo<,>)
Since we have two weaving methods, Attribute tag and interface implementation, it may be applied at the same time, and if the content of the two weaving is the same, there will be repeated weaving. In order to avoid this as much as possible In this case, when the interface is defined, mutually exclusive types can be defined, that is, only one can take effect at the same time, and which one takes effect is determined according to Priority (#Priority).
public class Mo1Attribute : MoAttribute
{
// ...
}
public class Mo2Attribute : MoAttribute
{
// ...
}
public class Mo3Attribute : MoAttribute
{
// ...
}
public class Test : IRougamo<Mo1Attribute, Mo2Attribute>
{
[Mo2]
public void M1()
{
// Mo2Attribute is applied to the method, the priority is higher than the Mo1Attribute implemented by the interface, and the Mo2Attribute will be applied
}
[Mo3]
public void M2()
{
// Mo1Attribute and Mo3Attribute are not mutually exclusive, both will be applied
}
}
Multitype Mutual Exclusion(IRepulsionsRougamo<,>)
IRougamo<,>
can only be mutually exclusive with one type, IRepulsionsRougamo<,>
can be mutually exclusive with multiple types.
public class Mo1Attribute : MoAttribute
{
}
public class Mo2Attribute : MoAttribute
{
}
public class Mo3Attribute : MoAttribute
{
}
public class Mo4Attribute : MoAttribute
{
}
public class Mo5Attribute : MoAttribute
{
}
public class TestRepulsion : MoRepulsion
{
public override Type[] Repulsions => new[] { typeof(Mo2Attribute), typeof(Mo3Attribute) };
}
[assembly: Mo2]
[assembly: Mo5]
public class Class2 : IRepulsionsRougamo<Mo1Attribute, TestRepulsion>
{
[Mo3]
public void M1()
{
// Mo1 is mutually exclusive with Mo2 and Mo3, but since Mo3 has a higher priority than Mo1, when Mo1 does not take effect, all mutually exclusive types will take effect.
// So eventually Mo2Attribute, Mo3Attribute, Mo5Attribute will be applied.
Console.WriteLine("m1");
}
[Mo4]
public void M2()
{
// Mo1 is mutually exclusive with Mo2 and Mo3, but since Mo1 has a higher priority than Mo2, Mo2 will not take effect
// Eventually Mo1Attribute, Mo4Attribute, Mo5Attribute will be applied
Console.WriteLine("m2");
}
}
<font color=red>Through the above example, you may notice that this multi-type mutual exclusion is not mutual exclusion between multiple types, but the mutual exclusion of
the first generic type and the type defined by the second generic type, and the second generic type is mutually exclusive. They are not mutually exclusive. Just like the
above example, when Mo1Attribute
does not take effect, the mutually exclusive Mo2Attribute
and Mo3Attribute
will take effect. It needs to be understood here that the
reason for defining mutual exclusion is the possible repeated application of Attribute and empty interface implementation, not to exclude all weaving repetitions. At the
same time, it is not recommended to use multiple mutual exclusion definitions, which is prone to logical confusion. It is recommended to carefully consider a set of
unified rules before application weaving, rather than random definitions, and then try to use multiple mutual exclusions to solve problems.</font>
Priority
IgnoreMoAttribute
- Method
MoAttribute
- Method
MoProxyAttribute
- Type
MoAttribute
- Type
MoProxyAttribute
- Type
IRougamo<>
,IRougamo<,>
,IRepulsionsRougamo<,>
- Assembly & Module
MoAttribute
Switch
Rougamo is developed by individuals. Due to limited capabilities, the research on IL is not so thorough, and with the development of .NET, some new types, new semantics and even new IL instructions will continue to appear. Therefore, there may exist Some bugs, and the bugs at the IL level may not be able to quickly locate the problem and fix it, so here is a switch to avoid code weaving without removing the Rougamo reference. Therefore, it is recommended that you use Rougamo for code weaving When the woven code does not affect the business, such as logs and APM. If you want to use static weaving components that are stable and can be quickly supported when you encounter problems, it is recommended to use PostSharp
Rougamo is developed on the basis of fody. After referencing Rougamo, the first compilation will generate a FodyWeavers.xml
file. The default content is as follows
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Rougamo />
</Weavers>
When you want to disable Rougamo, you need to add the attribute enabled
to the Rougamo
node of the configuration file and set the value to false
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Rougamo enabled="false" />
</Weavers>
Record yield return IEnumerable/IAsyncEnumerable return value
We know that using yield return
syntax sugar + IEnumerable
return value method, after calling the method, the code of the method is not actually executed, the actual
execution of the code is when you access the elements in the IEnumerable
object When, for example, you go to foreach this object or call ToList/ToArray
, and the
returned elements are not stored in an array/linked list (the specific principle is not explained here), so by default there is no The method directly obtains the
collection of all elements returned by yield return IEnumerable
.
But there may be some scenarios with strict code monitoring that need to record all return values, so in the implementation, I created an array to save all the returned elements,
but since this array is created additionally, it will take up additional memory space, and at the same time It is not clear how big the set of elements returned by this
IEnumerable
is, so in order to avoid excessive memory consumption, the return value of yield return IEnumerable
will not be recorded by default. The Rougamo
node of
FodyWeavers.xmladds attribute configuration
enumerable-returns="true"`.
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Rougamo enumerable-returns="true" />
</Weavers>
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.2.5)
- System.Threading.Tasks.Extensions (>= 4.5.4)
NuGet packages (42)
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
The AI 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 | 1,935 | 9/29/2024 | |
4.0.4-preview-1727349912 | 91 | 9/26/2024 | |
4.0.3 | 1,217 | 9/16/2024 | |
4.0.3-preview-1726120802 | 95 | 9/12/2024 | |
4.0.3-preview-1725957423 | 103 | 9/10/2024 | |
4.0.2 | 502 | 9/9/2024 | |
4.0.2-preview-1725956948 | 94 | 9/10/2024 | |
4.0.2-preview-1725875652 | 94 | 9/9/2024 | |
4.0.2-preview-1725466232 | 95 | 9/4/2024 | |
4.0.1 | 2,616 | 9/2/2024 | |
4.0.1-preview-1725141430 | 87 | 8/31/2024 | |
4.0.0 | 5,940 | 8/10/2024 | |
4.0.0-priview-1723306347 | 108 | 8/10/2024 | |
4.0.0-priview-1722831925 | 85 | 8/5/2024 | |
3.1.0 | 1,499 | 7/16/2024 | |
3.0.2 | 436 | 7/8/2024 | |
3.0.2-priview-1720363148 | 102 | 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,330 | 5/4/2024 | |
3.0.0-priview-1714754497 | 77 | 5/3/2024 | |
3.0.0-priview-1714407561 | 131 | 4/29/2024 | |
2.3.1 | 7,316 | 4/23/2024 | |
2.3.1-priview-1713854631 | 113 | 4/23/2024 | |
2.3.1-priview-1713791514 | 102 | 4/22/2024 | |
2.3.0 | 3,765 | 3/10/2024 | |
2.3.0-priview-1709894403 | 112 | 3/8/2024 | |
2.2.0 | 2,925 | 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 | 108 | 1/18/2024 | |
2.2.0-priview-1702899195 | 182 | 12/18/2023 | |
2.1.1 | 4,604 | 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,245 | 11/16/2023 | |
2.0.0 | 2,979 | 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 | 148 | 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,343 | 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,641 | 3/1/2023 | |
1.4.0-beta | 358 | 2/27/2023 | |
1.4.0-alpha | 233 | 2/25/2023 | |
1.3.4 | 56,057 | 2/17/2023 | |
1.3.3 | 976 | 1/17/2023 | |
1.3.2 | 18,224 | 12/20/2022 | |
1.3.1 | 341 | 12/20/2022 | |
1.3.1-beta | 178 | 12/14/2022 | |
1.3.0 | 1,280 | 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,781 | 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 | 174 | 6/24/2022 | |
1.1.0-alpha2 | 173 | 6/23/2022 | |
1.1.0-alpha1 | 176 | 6/22/2022 | |
1.1.0-alpha | 190 | 5/22/2022 | |
1.0.3 | 710 | 5/6/2022 | |
1.0.3-beta | 193 | 4/26/2022 | |
1.0.2 | 694 | 12/23/2021 | |
1.0.1 | 7,733 | 11/23/2021 | |
1.0.1-beta | 4,919 | 11/23/2021 |
Add ExMoAttribute, for methods whose return value is Task/Task<T>/ValueTask/ValueTask<T>, no matter whether async syntax is used or not, you can directly set the return value according to the return value type when using the async syntax.