Meat Loaf (/inversionhourglass/Rougamo), a compile-time AOP component. Compared to dynamic proxy AOP needs to be initialized at application startup , compile-time completion of the code weaving meat loafers reduce the application startup initialization time , while meat loafers also support all kinds of methods , whether the method is synchronous or asynchronous , static or instance , constructor or property are supported . Meat Loaf does not need to be initialized , write a good cut type can be applied directly to the corresponding method , while Meat Loaf also provides a method feature matching and class AspectJ expression matching batch application rules .
asynchronous cutout
Thanks to the changes made in 3.0 to the way facets are implemented, version 4.0 implements an asynchronous facet feature based on proxy weaving. What are asynchronous facets? To put it bluntly, it's a newOnEntry/OnSuccess/OnException/OnExit
Corresponding asynchronous methodsOnEntryAsync/OnSuccessAsync/OnExceptionAsync/OnExitAsync
。
How to use
To write an asynchronous cutover, you generally inherit theAsyncMoAttribute
maybeAsyncMo
and then rewrite theOnXxxAsync
Methods will suffice.
// Defining cutout types
public class TestAttribute : AsyncMoAttribute
{
public override async ValueTask OnEntryAsync(MethodContext) { }
public override async ValueTask OnSuccessAsync(MethodContext) { }
public override async ValueTask OnExceptionAsync(MethodContext) { }
public override async ValueTask OnExitAsync(MethodContext) { }
}
public class Cls
{
// Applying to synchronization methods
[Test]
public void M() { }
// Applying to asynchronous methods
[Test]
public static async Task MAsync() => ();
}
Talk about details.
After understanding how asynchronous facets are used you may have a question: what does a synchronous facet look like on an asynchronous method and what does an asynchronous facet look like on a synchronous method? Before answering this question, let's take a look at the followingAsyncMoAttribute
The source code for the
public abstract class AsyncMoAttribute : RawMoAttribute
{
public override ValueTask OnEntryAsync(MethodContext context) => default;
public override ValueTask OnExceptionAsync(MethodContext context) => default;
public override ValueTask OnSuccessAsync(MethodContext context) => default;
public override ValueTask OnExitAsync(MethodContext context) => default;
public sealed override void OnEntry(MethodContext context)
{
OnEntryAsync(context).ConfigureAwait(false).GetAwaiter().GetResult();
}
public sealed override void OnException(MethodContext context)
{
OnExceptionAsync(context).ConfigureAwait(false).GetAwaiter().GetResult();
}
public sealed override void OnSuccess(MethodContext context)
{
OnSuccessAsync(context).ConfigureAwait(false).GetAwaiter().GetResult();
}
public sealed override void OnExit(MethodContext context)
{
OnExitAsync(context).ConfigureAwait(false).GetAwaiter().GetResult();
}
}
As you can see from the source code, theAsyncMoAttribute
is the one that contains the synchronous facet methods, along with the default implementation, which implements the code by calling the asynchronous facet methods directly and thenGetResult
. Again, if you go to theMoAttribute
source code, you will see that theMoAttribute
It also has asynchronous facet methods, and the default implementation is to call synchronous facet methods. So, the answer to the question above is that the synchronous facet methods will be called in the synchronous methods and the asynchronous facet methods will be called in the asynchronous methods.
At this point you may have another question: since theAsyncMoAttribute
cap (a poem)MoAttribute
What's the point of having two classes when you have all the synchronous and asynchronous facet methods?
This is a design that combines convenience and security considerations. As mentioned earlier, Meatpacking will call synchronous cutout methods in synchronous methods and asynchronous cutout methods in asynchronous methods. If you don't separate the two classes and continue to useMoAttribute
Then first a question:MoAttribute
Should all the faceted methods in should be designed as abstract methods for subclasses to implement all synchronous asynchronous faceted methods, or should they be designed as dummy methods with default implementations for subclasses to rewrite the methods as they choose?
-
Choosing to design as an abstract method
Designing it as an abstract method adds extra work for subclasses to implement all the faceted methods at inheritance time. -
Choose to design as a dummy method with a default implementation
Choosing this approach brings up another question: whether the default implementation uses an empty method implementation, or whether it uses an inter-call between asynchronous and synchronous facets (calling synchronous facet methods by default in asynchronous facet methods, and calling asynchronous facet methods by default in synchronous facet methods)-
Realized using the null method
Since it is a virtual method, subclasses inherit theMoAttribute
It is not mandatory to override the virtual methods, so if you override a synchronous facet method but do not override the corresponding asynchronous facet method, it will result in the facet type behaving differently when applied to synchronous methods than to asynchronous methods, which is often not what is expected. -
Using inter-calls between asynchronous and synchronous facets
The same problem exists as with an empty method implementation, but with more serious consequences. For example, if you inherit theMoAttribute
Since you don't need to do anything when the method exits, you neither override theOnExit
Nor did it rewrite theOnExitAsync
then the method exits with a call toOnExit
maybeOnExitAsync
It will appear when theOnExit
cap (a poem)OnExitAsync
Recursive call.
-
Realized using the null method
From the above illustration, you should be able to understand the reason for dividing synchronous and asynchronous facets into two types. If you are observant and careful, you may have noticed that the aboveAsyncMoAttribute
The synchronized cutout methods in the source code also add thesealed
keyword, this is also to increase the security, prohibit rewriting, to avoid the rewrite method due to the IDE intelligent prompts to rewrite the synchronous cutout method but not rewrite the corresponding asynchronous method, resulting in synchronous cutout method and asynchronous cutout method performance inconsistency problems.
Fully customizable RawMoAttribute
this being the caseMoAttribute
cap (a poem)AsyncMoAttribute
The default implementation is to call the corresponding method directly, so what if I don't think the default implementation is optimal, for exampleAsyncMoAttribute
The default synchronization cutout is to call the asynchronous cutout directly and then wait for the synchronization to complete, I have a better synchronization solution, how should I do it, after all, the synchronization cutout methods all pass thesealed
Keywords are forbidden to be rewritten.
Careful you're checking aboveAsyncMoAttribute
As may have been discovered at the time of the source code, theAsyncMoAttribute
inherited fromRawMoAttribute
equalMoAttribute
Also inherited fromRawMoAttribute
。RawMoAttribute
Opens up all the synchronous asynchronous cutout methods, which are abstract methods that allow you to fully customize the synchronous asynchronous cutout. After inheriting theRawMoAttribute
When implementing synchronous asynchronous facet methods you need to pay attention to the previously mentioned: avoid differences in code logic between synchronous and asynchronous facets, and avoid recursive calls between synchronous and asynchronous facet methods.
Other updates
New Type
In addition to the above mentionedAsyncMoAttribute
cap (a poem)RawMoAttribute
The newest addition to the list is theRawMO
,MO
,AsyncMo
Respectively, withRawMoAttribute
,MoAttribute
,AsyncMoAttribute
counterpart, the difference being that the latter inherits fromAttribute
. This is because meatloaf can be applied in a way other than Attribute applications by theImplementing the empty interface IRougamo is applied in a way that does not require the type to be an Attribute subclass, and of course Attribute subclasses are accepted, the option of not inheriting Attribute is just provided here.
Forced Synchronization for Performance Optimization
In the introduction to asynchronous facets it was stated that synchronous methods will call synchronous facets and asynchronous methods will call asynchronous facets. This setting is a good one by default, but if your faceted operations don't involve asynchronous operations at all, you don't actually need to call asynchronous facets in asynchronous methods, because asynchronous facets walk a layer ofValueTask
packaging, there would be additional overhead compared to synchronized cuts. In this case, it is possible to pass theForceSync
attribute is set in an asynchronous method that needs to enforce a synchronous cutout:
public class TestAttribute : MoAttribute
{
// In asynchronous methods, OnEntry and OnExit will force the synchronous facet methods to be called.
public override ForceSync ForceSync => | ;
}
In fact, if the performance requirements are not so strict, it is possible not to set theForceSync
that the meat loaf has been adoptedValueTask
, the default asynchronous facet methods have very limited additional overhead for wrapping synchronous facet methods.
Special note on async void
As we talked about when 3.0 was released, the proxy weaving approach used since 3.0 has been very useful for theasync void
The support may not work the way you expect. For details, please jump to see theasync void special note。
caterasync void
is not a recommended use (It's not officially recommended either.), so the decision was not rightasync void
Do more adaptation work and continue to follow the 3.0 approach of putting theasync void
method as if it were an ordinaryvoid
The return value is viewed as a synchronized method. However, unlike 3.0, in version 4.0 if you find that theasync void
Methods with the meatloaf cutout type applied to them will generate an MSBuild alert at compile time. Alert messages are often not easy to notice if you are sure you don't want theasync void
If you want to apply the meat loaf cutout type, or if you want to be alerted when this occurs so that you can make the appropriate changes, then you can add thePropertyGroup
Add a new child node under the node<FodyTreatWarningsAsErrors>true</FodyTreatWarningsAsErrors>
This configuration will change the warning message generated by Fody to an error message, thus making the compilation fail for the purpose of alerting.
<Project Sdk="">
<PropertyGroup>
<FodyTreatWarningsAsErrors>true</FodyTreatWarningsAsErrors>
</PropertyGroup>
</Project>
MethodContext member changes
removingMethodContext
hit the nail on the headIsAsync
, IsIterator
, MosNonEntryFIFO
, Data
attribute, which sets theRealReturnType
Marked as obsolete and hidden, with a newTaskReturnType
attribute, which is the same as theRealReturnType
has a similar function.
Configuration file smart tips
Meatpacking has some license configuration items that can be found in thein the configuration, seeconfiguration item. Now add the corresponding xml schema for these configurations, after modifying the
(used form a nominal expression)
Rougamo
A smart tip will appear when the node.