iT邦幫忙

2

[AOP系列]用Autofac與Costle.Core的Interceptor來實作AOP架構

前言

在AOP系列文章的第一篇有提到使用Autofac.Extras.DynamicProxy的Interceptor來實現AOP架構,本篇文章就來詳細說明實作的方法。

Autofac 簡介

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,一共會有三個步驟。

  • 設計攔截器
  • 綁定攔截器
  • 服務Service掛載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;
                }
            }
        }
    }
}

綁定攔截器(Interceptor)

首先在專案的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);
    }
}

服務Service掛載Interceptor

要在服務類別掛載Interceptor,有兩種做法,第一種是直接在Service上面加入Intercept標籤,並且標註Interceptor的類型,如下。

做法A:在Service掛載Interceptor標籤

[Intercept(typeof(ExceptionLogInterceptor))]
public class TestService : IService
{
	
}

第二種作法更全面也更簡單一些,只要在剛剛的AutofacConfig綁定就好,就可以不用一個一個Service加上標籤,語法如下。

作法B:在AutofacConfig就綁定Interceptor

//註冊Interface並綁定Interceptor
builder.RegisterType<TestService>()
	   .As<IService>()
	   .EnableInterfaceInterceptors()
	   //以下兩行綁定Interceptor
	   .InterceptedBy(typeof(ExceptionHandleInterceptor));

所以在Service上面的Intercept標籤就可以移除。

//這行可以拿掉
[Intercept(typeof(ExceptionLogInterceptor))]

產生帶有Interceptor的Service物件

綁定結束後,若要使用帶有Interceptor的Service,記得不能直接new一個服務類別,要用以下語法,透過Autofac來產生服務類別,Interceptor才有效用。

 var service = AutofacConfig.container.Resolve<TService>();
 service.Function();

執行Function後結果

在TestService內,加入一個TestFunctionWithException方法,來進行測試,變更後的程式碼如下。

方法內容

public class TestService : IService
{
	public int TestFunctionWithException(int x, int y)
    {
        //直接拋出錯誤訊息為 Test Error的例外
        throw new Exception("Test Error.");
    }
}

Log紀錄內容

2019-11-04 18:20:55.3275 | ERROR | RuntimeMethodInfo | 引動過程的目標傳回例外狀況。 | System.Reflection.TargetInvocationException: 引動過程的目標傳回例外狀況。 ---> System.Exception: Test Error.
   於 .......

可以看到Test Error已經被自動記錄到所設定的Log檔案。

自訂Interceptor

若是想要自己定義一個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) 動態代理


尚未有邦友留言

立即登入留言