在.NET專案中使用PostSharp

PHPz
發布: 2017-03-12 15:48:55
原創
4903 人瀏覽過

PostSharp是一種Aspect Oriented Programming 面向切面(或面向方面)的元件框架,適用在.NET開發中,本篇主要介紹Postsharp在.NET開發中的相關知識,以及一些如日誌、快取、交易處理、異常處理等常用的切面處理操作。

AOP(Aspect-Oriented Programming)是一種將函數的輔助性功能與業務邏輯相分離的程式設計泛型(programming paradigm),其目的是將橫切關注點(cross-cutting concerns)分離出來,使得程式具有更高的模組化特性。 AOP是面向方面軟體開發(Aspect-Oriented Software Development)在編碼實現層面的具體表現。

我們知道,解耦是程式設計師編碼開發過程中一直追求的,AOP也是為了解耦所誕生。引入AOP技術,能很大程度簡化我們編碼,減少複製的程式碼量,也便於統一維護統一的部分程式碼,如日誌、快取、事務處理、異常處理等常用的處理。

1、AOP框架的介紹

1)AOP技術介紹

AOP技術利用一種稱為「橫切」的技術,剖解開封裝的物件內部,並將那些影響了多個類別的公共行為封裝到一個可重複使用模組,並將其名為“Aspect”,即方面。所謂“方面”,簡單地說,就是將那些與業務無關,卻為業務模組所共同調用的邏輯或責任封裝起來,便於減少系統的重複代碼,降低模組間的耦合度,並有利於未來的可操作性和可維護性。 AOP代表的是一個橫向的關係,如果說「物件」是一個空心的圓柱體,其中封裝的是物件的屬性和行為;那麼面向方面程式設計的方法,就彷彿一把利刃,將這些空心圓柱體剖開,以獲得其內部的消息。而剖開的切面,也就是所謂的「面向」了。然後它又以巧奪天功的妙手將這些剖開的切面復原,不留痕跡。

使用「橫切」技術,AOP把軟體系統分成兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點。橫切關注點的一個特點是,他們經常發生在核心關注點的多處,而各處都基本相似。例如權限認證、日誌、事務處理。 Aop 的作用在於分離系統中的各種關注點,將核心關注點和橫切關注點分開。正如Avanade公司的高級方案構架師Adam Magee所說,AOP的核心思想就是“將應用程序中的商業邏輯同對其提供支持的通用服務進行分離。”

 

2)AOP使用場景

#AOP用來封裝橫切關注點,具體可以在下面的場景中使用:

Authentication 權限

Caching 快取

Context passing 內容傳遞

Error handling 錯誤處理

Lazy loading 懶載入

Debugging  調試

logging, tracing, profiling and monitoring 記錄追蹤最佳化校準

##Per

for##Performance optimization 效能最佳化

Persistence  持久化

Resource pooling 資源池

#Syn##chr## pooling 資源池

#Syn##chr

#onization 同步Trans

action

s 交易

 

3)PostSharp框架

####PostSharp是一個用於在.NET平台上實現AOP的框架,是比較常用的一個AOP框架,官方網站為http://www.php.cn/。目前最新版本為4.X,但是是收費的AOP軟體。 ###

PostSharp使用靜態織入方式實現AOP,其連接點非常豐富,使用簡單,而且相對其它一些.NET平台上的AOP框架來說,PostSharp較為輕量級,但是功能卻一點也不遜色。

整體來說,使用PostSharp,將會帶來以下優點:

  • #橫切關注點單獨分離出來,提高了程式碼的清晰性和可維護性。

  • 只要在Aspect中寫輔助功能程式碼,在一定程度上減少了工作量和冗餘程式碼。

當然,使用PostSharp也會存在一些缺點,主要缺點有如下兩方面:

  • 增加了除錯的難度。

  • 比起不用AOP的程式碼,運作效率有所降低。

不過瑕不掩瑜,相對於這些缺點問題,使用PostSharp可以大幅提高開發效率,減少重複程式碼,從而提高程式碼的可讀性、可維護性。

另外在GitHub上還有一些開源的AOP元件,例如排頭位的是KingAOP(http://www.php.cn/),不過由於它採用了Dynamic的方式來實現,如它的構造物件如下所示。


dynamic helloWorld = new HelloWorld();
helloWorld.HelloWorldCall();
登入後複製

因此雖然比較方便,而且號稱和PostSharp使用習慣類似,但是改變了物件的建立方式,對一般專案的類別物件處理並不太適合。因此我還是比較傾向使用PostSharp來進行AOP的程式開發。

 

2、PostSharp框架的使用

1)準備PostSharp的編譯環境

PostSharp目前版本是4.x ,我在官網下載了進行使用,不過經常發生"Error connecting to the pipe server. See previous warnings for details.",後來乾脆使用了3.x版本的,反而能夠正常使用,非常不錯,呵呵。

PostSharp是一個可以安裝在VS上的插件,安裝後在VS的選單欄位裡面增加了一個PostSharp的選單項,如下圖所示。

一般專案如果需要使用PostSharp特性的,在專案屬性的【PostSharp】選項頁中,使用【Add PostSharp to this project】把PostSharp加入到專案裡面進行使用。

 新增後,會跳出PostSharp的外掛程式提示對話框,提示將加入對應的PostSharp套件等內容,如下所示。

完成後就可以在專案中使用PostSharp的相關類別了。

 

2)增加PostSharp的AOP切面處理

一般約定每個Aspect類別的命名必須為「XXXAttribute」的形式。其中「XXX」就是這個Aspect的名字。 PostSharp中提供了豐富的內建“Base Aspect”以便我們繼承,其中這裡我們繼承“OnMethodBoundaryAspect ”,這個Aspect提供了進入、退出函數等連接點方法。另外,Aspect上必須設定“[Serializable] ”,這與PostSharp內部對Aspect的生命週期管理有關。

日誌的Aspect類別的程式碼如下所示。


    [Serializable]    public class LogAttribute : OnMethodBoundaryAspect
    {        public override void OnEntry(MethodExecutionArgs args)
        {
            Console.WriteLine(Environment.NewLine);

            Console.WriteLine("Entering [ {0} ] ...", args.Method);            base.OnEntry(args);
        }        public override void OnExit(MethodExecutionArgs args)
        {
            Console.WriteLine("Leaving [ {0} ] ...", args.Method);            base.OnExit(args);
        }
    }
登入後複製

異常處理的類別程式碼如下所示。


    [Serializable]    public class ExceptionAttribute : OnExceptionAspect
    {        public override void OnException(MethodExecutionArgs args)
        {
            Console.WriteLine(String.Format("Exception in :[{0}] , Message:[{1}]", args.Method, args.Exception.Message));
            args.FlowBehavior = FlowBehavior.Continue;            base.OnException(args);
        }
    }
登入後複製

計時處理的Aspect類別程式碼如下所示。


    [Serializable]
    [MulticastAttributeUsage(MulticastTargets.Method)]    public class TimingAttribute : PostSharp.Aspects.OnMethodBoundaryAspect
    {
        [NonSerialized]
        Stopwatch _StopWatch;        public override void OnEntry(PostSharp.Aspects.MethodExecutionArgs args)
        {
            _StopWatch = Stopwatch.StartNew();            base.OnEntry(args);
        }        public override void OnExit(PostSharp.Aspects.MethodExecutionArgs args)
        {
            Console.WriteLine(string.Format("[{0}] took {1}ms to execute",              new StackTrace().GetFrame(1).GetMethod().Name,
                _StopWatch.ElapsedMilliseconds));            base.OnExit(args);
        }
    }
登入後複製

事務處理的Aspect類別程式碼如下所示。


    [Serializable]
    [AspectTypeDependency(AspectDependencyAction.Order, AspectDependencyPosition.After, typeof(LogAttribute))]    public class RunInTransactionAttribute : OnMethodBoundaryAspect
    {
        [NonSerialized]
        TransactionScope TransactionScope;        public override void OnEntry(MethodExecutionArgs args)
        {            this.TransactionScope = new TransactionScope(TransactionScopeOption.RequiresNew);
        }        public override void OnSuccess(MethodExecutionArgs args)
        {            this.TransactionScope.Complete();
        }        public override void OnException(MethodExecutionArgs args)
        {
            args.FlowBehavior = FlowBehavior.Continue;
            Transaction.Current.Rollback();
            Console.WriteLine("Transaction Was Unsuccessful!");
        }        public override void OnExit(MethodExecutionArgs args)
        {            this.TransactionScope.Dispose();
        }
    }
登入後複製

下面是幾個Aspect類別的切面處理程式碼,如下所示。


        [Exception]
        [Log]        static void Calc()
        {            throw new pideByZeroException("A Math Error Occured...");
        }

        [Log, Timing]        static void LongRunningCalc()
        {            //wait for 1000 miliseconds
            Thread.Sleep(1000);
        }
登入後複製

從上面我們可以看到,常規的異常處理、日誌處理都已經透過Attribute的方式進行處理了,在函數體裡面都只是剩下具體的業務邏輯程式碼了,這樣大大提高了程式碼的可讀性,簡潔明了。

運行上面的程式碼函數的調用,我們可以在輸出日誌裡面看到具體的結果內容。


Entering [ Void Calc() ] ...
“System.pideByZeroException”类型的第一次机会异常在 PostSharpExample.exe 中发生
Exception in :[Void Calc()] , Message:[A Math Error Occured...]
Leaving [ Void Calc() ] ...


Entering [ Void LongRunningCalc() ] ...
Leaving [ Void LongRunningCalc() ] ...
[LongRunningCalc] took 1002ms to execute
登入後複製

这样,通过声明的方式,就实现了常规日志 、异常的处理,当然实际项目上使用日志、异常处理的这些代码肯定会更加复杂一些,不过小例子已经实现了切面逻辑的分离处理了,尘归尘、土归土,一切都是那么的简洁安静了。

 

以上是在.NET專案中使用PostSharp的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!