AspectInjector 是一套開源的 AOP套件使用起來相當簡便而且支援 async await。
AspectInjector 使用方法跟 ActionFilter 有點類似。先建立Attribute 之後在要套用的方法或類別上加上 tag。
首先安裝好AspectInjector
假設我們要建立一個負責寫Log的Class
[Aspect(Scope.Global)]
public class WriteLog
{ [Advice(Kind.Before, Targets = Target.Method)]
public void Before()
{
Console.WriteLine("Method Begin");
}[Advice(Kind.After, Targets = Target.Method)]
public void After()
{
Console.WriteLine("Method After");
}
}
其中Aspect 是設定物件的生命週期,有 Glbal與 PerInstance兩種模式可以選擇 Global 表示物件將建立為singleton,反之為 Transient 隨攔截物件一同建立與消滅。
Adivce 定義進入點與攔截的目標。Kind 有Before、After、Around 三種屬性、Target 的有非常多列舉,一般常用應該都包在裡面了,如果要一次增加多組條件可以使用 | 串接 ex :Targets = Target.Method |Target.Public
簡單的定義好物件之後接下來就是建立攔截器
[Injection(typeof(WriteLog))]public class WriteLogAttribute : Attribute{}
Injection 表示要載入的 Aspect 物件。可以加載多個 Injection ,也可以加載自己。若加載多個Injection,則加載順序是由上而下、由內而外依序加載。
之後在要記錄 Log的目標上加上 tag就可以了
class Program{static void Main(string[] args)
{
DoSomething();
Console.ReadKey();
}[WriteLog]
static void DoSomething()
{
Console.WriteLine("Work");
}
}
運行結果如下
另外 AspectInjector 可以透過 Argument 來取得攔截目標的入參等各種屬性。
假設我們要再加上計時器,計算耗費時間
[Aspect(Scope.Global)]
public class SpendTime
{
private Stopwatch _timer = new Stopwatch();[Advice(Kind.Around, Targets = Target.Method)]
public object Around(
[Argument(Source.Arguments)] object[] arguments,[Argument(Source.Target)] Func<object[], object> target)
{
_timer.Start();//Around 會截停目標方法,所以需自行執行然後返回結果,否則會出錯
var result = target(arguments);_timer.Stop();Console.WriteLine("spend "+ _timer.ElapsedTicks);_timer.Reset();return result;
}[Advice(Kind.Before, Targets = Target.Method)]
public void Before()
{
Console.WriteLine("Before SpendTime");
}[Advice(Kind.After, Targets = Target.Method)]
public void After()
{
Console.WriteLine("After SpendTime");
}}
完成後一樣加上Injection
[Injection(typeof(WriteLog))]
[Injection(typeof(SpendTime))]public class WriteLogAttribute : Attribute{}
執行後結果如下