CompileTimeWeaver.Fody
3.3.5
dotnet add package CompileTimeWeaver.Fody --version 3.3.5
NuGet\Install-Package CompileTimeWeaver.Fody -Version 3.3.5
<PackageReference Include="CompileTimeWeaver.Fody" Version="3.3.5" />
paket add CompileTimeWeaver.Fody --version 3.3.5
#r "nuget: CompileTimeWeaver.Fody, 3.3.5"
// Install CompileTimeWeaver.Fody as a Cake Addin #addin nuget:?package=CompileTimeWeaver.Fody&version=3.3.5 // Install CompileTimeWeaver.Fody as a Cake Tool #tool nuget:?package=CompileTimeWeaver.Fody&version=3.3.5
The nuget package
Installation:
PM> Install-Package CompileTimeWeaver.Fody
DotNet Platforms
- NetStandard 2.0
Compile time IL rewriting tool for AOP implementation
Different from runtime interception with dynamic proxy, this tool rewrites assembly at VisualStudio/MSBuild build time, so that your code get these achievements that dynamic proxy based enhancement cannot give:
- Much better performance, no dynamic proxy, no thread block or reflection at run time.
- Directly instantiate your weaved classes with C# ""new"" operator
- Weave virtual methods/properties
- Weave static methods/properties
- Weave extension methods
- Weave constructors
- Add property changed notification to auto-properties
Advice Based Programming Model
Start with version 2, this tool support only advice based programming model. An advice is created in C# as an attribute derived from AdviceAttribute class.
- Easy to intercept async method without thread blocking
- Simple to control the flow and add "before", "after", "around" and "exception" advices
- Allow to advise methods with parameters of reference type, value type and generic type, ref parameters and out parameters are allowed, too.
Your Code
using CompileTimeWeaver;
public class MyAdvice : AdviceAttribute
{
public override object Advise(IInvocation invocation)
{
// do something before target method is Called
// ...
Trace.WriteLine("Entering " + invocation.Method.Name);
try
{
return invocation.Proceed(); // call the next advice in the "chain" of advice pipeline, or call target method
}
catch (Exception e)
{
// do something when target method throws exception
// ...
Trace.WriteLine("MyAdvice catches an exception: " + e.Message);
throw;
}
finally
{
// do something after target method is Called
// ...
Trace.WriteLine("Leaving " + invocation.Method.Name);
}
}
public override async Task<object> AdviseAsync(IInvocation invocation)
{
// do something before target method is Called
// ...
Trace.WriteLine("Entering async " + invocation.Method.Name);
try
{
return await invocation.ProceedAsync().ConfigureAwait(false); // asynchroniously call the next advice in advice pipeline, or call target method
}
catch (Exception e)
{
// do something when target method throws exception
// ...
Trace.WriteLine("MyAdvice catches an exception: " + e.Message);
throw;
}
finally
{
// do something after target method is Called
// ...
Trace.WriteLine("Leaving async " + invocation.Method.Name);
}
}
}
[MyAdvice]
public class MyClass
{
public int Add(int x, int y)
{
return x + y;
}
public Task<int> AddAsync(int x, int y)
{
await Task.Dely(1000).ConfigureAwait(false);
return x + y;
}
}
The MyAdvice class and MyClass class can be in different assemblies. Now use your MyClass as below:
var obj = new MyClass();
int z = obj.Add(1, 2);
z = await obj.AddAsync(1,2);
Debug your code, you will see your Add() method and AddAsync() method were magically rewritten, and the output is as below:
Entering .ctor... Leaving .ctor... Entering Add... Leaving Add... Entering AddAsync... Leaving AddAsync...
The first time when you compile your project, FodyWeavers.xml and FodyWeavers.xsd are generated if they do not exist yet. FodyWeavers.xml content likes this below. Usally you do not need to change the generated FodyWeavers.xml file at all.
<?xml version="1.0" encoding="utf-8"?>
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<CompileTimeWeaver />
</Weavers>
Notes:
- When multiple advices are applied to a method, the advices are invoked as a pipe line, the Advise() or AdviseAsync() of the first advice is called first.
- When an advice is applied to class level, it is identical to this advice is added on each constructor and each method.
- Class level advices appears before all constructor/method level advices
- Each advice is assigned an Order, it is the sequence number of the appearance in the type group.
- Each advice on a recursive method is invoked only when the method was entered at the very first time, re-entrances don't invoke the advice again, for performance reason.
Built-in advices
There are some built-in advices that you can take advantage in your code.
- NotifyPropertyChangedAttribute
When NotifyPropertyChangedAttribute is applied to a class, the class automatically implements INotifyPropertyChanged interface (if it is not implemented) and the setters of auto properties fire PropertyChanged event when the property values change.
If you do not want a specific setter to fire event, just apply IgnoreNotifyPropertyChangedAttribute to the property, the setter will not be rewritten.
[NotifyPropertyChanged]
public class MyClass //: INotifyPropertyChanged - optional
{
//public event PropertyChangedEventHandler PropertyChanged; - optional
public string Name { get; set; }
public int Age { get; set; }
[IgnoreNotifyPropertyChanged]
public string Password { get; set; }
}
One property change may cause the other property changes, DeterminedByPropertiesAttribute is used to define dependancy relations between properties. In the code below, the change of property A fires property change events for property A, C and D.
[NotifyPropertyChanged]
public class MyClass //: INotifyPropertyChanged - optional
{
public int A { get; set; }
public int B { get; set; }
[DeterminedByProperties("A")]
public int C => A + 1;
[DeterminedByProperties("B","C")]
public int D => B + C;
}
- LoggingAttribute
When LoggingAttribute is applied to a class or a method, the parameters of the constructor and methods are written into NLog, Log4Net or Serilog, depending on what logging package is enabled. [IgnoreLogging] is used to disable sensitive parameter logging. For example:
[Logging]
public class ClassWithLog
{
public static void MethodWithLog(string userName, [IgnoreLogging]string password, int x, int y)
{
...
}
[IgnoreLogging]
public static int MethodWithoutLog(int x, int y)
{
...
}
}
//The example application using Serilog
using Serilog;
class Program
{
static void Main(string[] args)
{
Serilog.Log.Logger = new Serilog.LoggerConfiguration()
.MinimumLevel.Debug()
.Enrich.FromLogContext()
.WriteTo.Console()
.CreateLogger();
ClassWithLog.MethodWithLog("Simon", "fdhasdewjsdfsdfe", 1, 2); //parameters except password are logged
ClassWithLog.MethodWithoutLog(1, 2); //parameters are not logged
Serilog.Log.CloseAndFlush();
}
}
When ClassWithLog.MethodWithLog method is called, you will see log messages as below, parameter values in log are from their ToString() method, and password parameter is not logged because of [IgnoreLogging] on it.
MethodWithLog...
userName: Simon
x: 1
y: 2
MethodWithLog completed in 5 milliseconds.
When ClassWithLog.MethodWithoutLog method is called, nothing is logged because it is decorated with [IgnoreLogging].
- ExceptionHandlerAttribute
ExceptionHandler Attribute is an advice to consolidate exception handling logic into specific classes according to the exception types. In the example code below, the ApplicationExceptionHandler class defines ApplicationException handling logic and the IOnExceptionHandler class defines IOException hanlding logic, you simply add ExceptionHandler decorations on the methods (HelloAsync as example below) to intercept the exceptions.
public class MyClass
{
[ExceptionHandler(typeof(ApplicationException), typeof(ApplicationExceptionHandler))]
[ExceptionHandler(typeof(IOException), typeof(IOExceptionHandler))]
public async Task<int> HelloAsync()
{
await Task.Delay(1).ConfigureAwait(false);
...
throw new ApplicationException();
...
throw new IOException();
}
}
internal class ApplicationExceptionHandler : IExceptionHandler
{
public bool HandleException(Exception e)
{
Trace.WriteLine(e.GetType() + " is caught");
return false;
}
}
internal class IOExceptionHandler : IExceptionHandler
{
public bool HandleException(Exception e)
{
Trace.WriteLine(e.GetType() + " is caught");
return false;
}
}
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.6.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on CompileTimeWeaver.Fody:
Package | Downloads |
---|---|
CompileTimeAOP.TransactionAwareness
A VisualStudio tool to allow programmers to develop Transaction Aware classes for NHibernate. TransactionAware AOP is implemented at compile time with CompileTimeWeaver.Fody. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
3.3.5 | 1,333 | 4/1/2024 |
3.3.4 | 3,661 | 2/1/2023 |
3.3.3 | 786 | 1/1/2022 |
3.1.7 | 1,686 | 2/6/2019 |
2.3.0 | 28,097 | 5/2/2017 |
2.2.1 | 1,436 | 4/30/2017 |
2.1.1 | 1,523 | 4/9/2017 |
2.1.0 | 1,035 | 4/9/2017 |
2.0.1 | 1,087 | 3/26/2017 |
2.0.0 | 1,031 | 3/24/2017 |
1.4.3 | 1,514 | 3/11/2017 |
1.4.2 | 1,516 | 3/8/2017 |
1.4.1 | 1,590 | 3/8/2017 |
1.3.0 | 1,475 | 2/27/2017 |
1.1.0 | 1,303 | 2/23/2017 |
1.0.0 | 1,073 | 2/23/2017 |
Support Netstandard 2.0; Add property notification to auto-properties