Rougamo.Fody 1.2.0-alpha2

This is a prerelease version of Rougamo.Fody.
There is a newer version of this package available.
See the version list below for details.
dotnet add package Rougamo.Fody --version 1.2.0-alpha2                
NuGet\Install-Package Rougamo.Fody -Version 1.2.0-alpha2                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Rougamo.Fody" Version="1.2.0-alpha2" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Rougamo.Fody --version 1.2.0-alpha2                
#r "nuget: Rougamo.Fody, 1.2.0-alpha2"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Rougamo.Fody as a Cake Addin
#addin nuget:?package=Rougamo.Fody&version=1.2.0-alpha2&prerelease

// Install Rougamo.Fody as a Cake Tool
#tool nuget:?package=Rougamo.Fody&version=1.2.0-alpha2&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

  1. IgnoreMoAttribute
  2. Method MoAttribute
  3. Method MoProxyAttribute
  4. Type MoAttribute
  5. Type MoProxyAttribute
  6. Type IRougamo<>, IRougamo<,>, IRepulsionsRougamo<,>
  7. 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 configurationenumerable-returns="true"`.

<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
  <Rougamo enumerable-returns="true" />
</Weavers>
Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.3.0 is deprecated because it has critical bugs.
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 is deprecated.
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.3 is deprecated because it has critical bugs.
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.