D-10 AoP ? autofac ? DynamicProxy

Service怎麼做到像MiddleWare一樣的東西

在網頁程式中可以透過MiddleWare來做到關注點分離,但是那是在請求中可以去攔截跟處理請求,如果今天腳色換成Service之類的程式該如何處理呢,這就是我們今天要介紹的內容AoP。

AoP

「天啊~~~我要怎麼處理每個方法的輸入輸出的log阿。」
一進辦公室小光就聽到大頭的慘叫聲,因為大頭昨天在追一個bug追到沒有方向,所以今天一大早大頭決定要先把每個方法加上輸入跟輸出的log。
「你知道甚麼是AoP嗎」
聽到大頭的慘叫後老K這麼問題,這時大頭像找到救星一般臉上露出了曙光。
「前輩,救救我吧。」
所以今天就跟著小光還有大頭了解一下甚麼是AoP以及在dotnetcore做到AoP。

甚麼是AoP

AoP就是剖面導向程式設計,白話文就是如同關注點分離,對於開發的程式關注於本身的邏輯開發,而其他與本身邏輯無關的功能就從程式中抽離,然後在像切蛋糕一樣切開來把額外的功能加到程式內,就如同一開始的大頭在本身的程式內沒有日誌的功能,所以現在我們在攔截原來的程式並在這裡加入日誌的功能。不過說那麼多在dotnetcore內該如何處理呢,接下來我們介紹DynamicProxy這個套件。

DynamicProxy

所以我們在dotnetcore中實作AoP就是透過dynamicproxy這個套件,所以接下來我們說明如何透過autofac及dynamicproxy做到AoP。

環境處理

在介紹如何撰寫程式做到AoP之前先說明我們需要使用到哪些套件,接下來我們先安裝以下兩個套件即可。

dotnet add package Autofac.Extras.DynamicProxy
dotnet add package Autofac.Extensions.DependencyInjection

實作攔截者

在安裝完套件之後我們開始來開發AoP,首先假設我們的需求是開發一個寄送email的服務,但是我們需要輸入及輸出的參數,所以我們先定義介面以及實作。

public interface IEmailService
{
     string Send(string message);
}

[Intercept(typeof(CallLogger))]
public class EmailService : IEmailService
{
    public string Send(string message)
    {
        return message;
    }
}

在實作時我們透過Intercept這個屬性來注入攔截者,接下來說明攔截者怎麼實作。

public class CallLogger : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        Console.WriteLine($"You are invoke {invocation.Method.Name}, args:{JsonSerializer.Serialize(invocation.Arguments)}");
        invocation.Proceed();
        Console.WriteLine($"You are finished {invocation.Method.Name}, result:{JsonSerializer.Serialize(invocation.ReturnValue)}");
    }
}

主要攔截者就是繼承IInterceptor並實作public void Intercept(IInvocation invocation)這個方法,這邊注意invocation.Proceed();就是執行被攔截的方法,所以我們把需要做的需求寫在那方法之前跟之後即可。最後來說明如何註冊攔截者跟本來的程式。

builder.Register(c => new CallLogger());
builder.RegisterType<EmailService>().As<IEmailService>().InstancePerDependency().EnableInterfaceInterceptors();

插入攔截器的方法有下列兩種。

EnableClassInterceptors 產生一個類別繼承要攔截的類別,所以方法要加virtual才能攔截
EnableInterfaceInterceptors 動態產生一個代理接口

除了透過Attribute之外,還可以在注入時加上,所以注入攔截器的方法有下列兩種。

加Attribute [Intercept(typeof(CallLogger))]
注入攔截器 builder.RegisterType().As().InterceptedBy(typeof(CallLogger)).InstancePerDependency().EnableInterfaceInterceptors();

後記

透過AoP可以把一般物件中做到關注點分離,如此不只在處理請求中,甚至於在處理一般的函式都可以專注在該函式主要處理的邏輯上,而其它非需要關注的邏輯就抽到攔截者來處理。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *