在AOP系列文章的第一篇有提到使用Autofac.Extras.DynamicProxy
的Interceptor來實現AOP架構,本篇文章就來詳細說明實作的方法。
Autofac是一個Ioc
容器,Ioc為英文Inversion of Control
控制反轉的意思,控制反轉是物件導向程式設計中的一種設計原則,可以用來減低電腦代碼之間的耦合度。其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI),還有一種方式叫「依賴尋找」(Dependency Lookup)。通過控制反轉,物件在被建立的時候,由一個調控系統內所有物件的外界實體,將其所依賴的物件的參照傳遞(注入)給它。
以上說明參考維基
要套用Autofac的Interceptor,主要需要安裝三個套件分別是:
Autofac
Autofac.Extras.DynamicProxy
Castle.Core
Castle.Core
主要功能是用來定義Interceptor的,而Autofac.Extras.DynamicProxy
的功能是來將Interceptor與Autofac綁定在一起,讓有在DI Container註冊的服務(Service class)可以擁有AOP的功能,所以在實現AOP架構上,三者缺一不可。
從無到有設定攔截器Interceptor,一共會有三個步驟。
設定之後再來就是看結果,以下就讓我慢慢說明,正篇開始囉!
以例外處理為例,並使用NLog套件記錄錯誤資訊,程式碼如下。
/// <summary>
/// 例外處理Interceptor
/// </summary>
public class ExceptionHandleInterceptor : IInterceptor
{
/// <summary>
/// 例外處理內容
/// </summary>
/// <param name="invocation"></param>
public void Intercept(IInvocation invocation)
{
//初始化NLog
var logger = LogManager.GetLogger(invocation.GetType().FullName);
try
{
//執行方法
invocation.Proceed();
}
catch (Exception ex)
{
//若有例外發生,進行下列處理
//若回傳值類型不為void
if (invocation.Method.ReturnType != typeof(void))
{
try
{
//嘗試傳回初始值
invocation.ReturnValue =
Activator.CreateInstance(invocation.Method.ReturnType);
}
catch
{
//失敗則傳回null
invocation.ReturnValue = null;
}
}
}
}
}
首先在專案的AppStart資料夾新增一個AutofacConfig.cs,用來先設定Autofac,註冊需要套用Autofac的服務(Service class),這邊我會用一層Interface來讓Service的Class繼承,所以註冊的時候是用Interface來註冊,程式碼如下。
public class AutofacConfig
{
public static IContainer container;
public static void Bootstrap()
{
var builder = new ContainerBuilder();
//註冊服務 TestService
//TestService繼承於IService介面
//並且允許掛載攔截器
builder.RegisterType<TestService>()
.As<IService>()
.EnableInterfaceInterceptors();
//註冊例外處理Interceptor
builder.RegisterType(typeof(ExceptionHandleInterceptor));
container = builder.Build();
}
}
接著在專案的Startup.cs,執行AutofacConfig的設定
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
//執行Autofac的設定
AutofacConfig.Bootstrapper(app);
}
}
要在服務類別掛載Interceptor,有兩種做法,第一種是直接在Service上面加入Intercept標籤,並且標註Interceptor的類型,如下。
[Intercept(typeof(ExceptionLogInterceptor))]
public class TestService : IService
{
}
第二種作法更全面也更簡單一些,只要在剛剛的AutofacConfig綁定就好,就可以不用一個一個Service加上標籤,語法如下。
//註冊Interface並綁定Interceptor
builder.RegisterType<TestService>()
.As<IService>()
.EnableInterfaceInterceptors()
//以下兩行綁定Interceptor
.InterceptedBy(typeof(ExceptionHandleInterceptor));
所以在Service上面的Intercept標籤就可以移除。
//這行可以拿掉
[Intercept(typeof(ExceptionLogInterceptor))]
綁定結束後,若要使用帶有Interceptor的Service,記得不能直接new一個服務類別,要用以下語法,透過Autofac來產生服務類別,Interceptor才有效用。
var service = AutofacConfig.container.Resolve<TService>();
service.Function();
在TestService內,加入一個TestFunctionWithException方法,來進行測試,變更後的程式碼如下。
public class TestService : IService
{
public int TestFunctionWithException(int x, int y)
{
//直接拋出錯誤訊息為 Test Error的例外
throw new Exception("Test Error.");
}
}
2019-11-04 18:20:55.3275 | ERROR | RuntimeMethodInfo | 引動過程的目標傳回例外狀況。 | System.Reflection.TargetInvocationException: 引動過程的目標傳回例外狀況。 ---> System.Exception: Test Error.
於 .......
可以看到Test Error已經被自動記錄到所設定的Log檔案。
若是想要自己定義一個Interceptor,則新增類別並繼承IInterceptor介面,範本如下,請記得invocation.Proceed()
還是要寫上去,讓你的Interceptor處理完他的事情後,方法可以繼續進行。
public class CustomInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
//what you want to do....
//↓↓↓↓繼續執行↓↓↓↓
invocation.Proceed();
}
}
本篇文章示範了使用Autofac的Interceptor功能來實作AOP,過程其實並不難,這麼簡單的幾個步驟,就可以省去不少重工,所取得的效益十分的高,希望能夠幫到各位夥伴們。在這邊各位也許會有以下疑問,若不使用Autofac,是否也能實現AOP的框架?
下篇即將介紹,敬請期待。
[AOP系列]簡單介紹AOP的概念
AOP 觀念與術語
Autofac + Interceptors(AOP) 動態代理