C# AOP學習筆記

来源:https://www.cnblogs.com/atomy/archive/2020/03/17/12467682.html
-Advertisement-
Play Games

一、AOP概念 官方解釋:AOP(Aspect-Oriented Programming,面向切麵編程),它是可以通過預編譯方式和運行期動態代理實現在不修改源代碼的情況下給程式動態統一添加功能的一種技術。它是一種新的方法論,是對傳統OOP編程的一種補充。OOP是關註將需求功能劃分為不同的並且相對獨立 ...


    一、AOP概念

    官方解釋:AOP(Aspect-Oriented Programming,面向切麵編程),它是可以通過預編譯方式和運行期動態代理實現在不修改源代碼的情況下給程式動態統一添加功能一種技術。它是一種新的方法論,是對傳統OOP編程的一種補充。OOP是關註將需求功能劃分為不同的並且相對獨立、封裝良好的類,並讓它們有著屬於自己的行為,依靠繼承和多態等來定義彼此的關係;AOP是希望能夠將通用需求功能從不相關的類當中分離出來,能夠使得很多類共用一個行為,一旦發生變化,不必修改很多類,而只需要修改這個為即可。AOP是使用切麵(aspect)將橫切關註點模塊化,OOP是使用類將狀態和行為模塊化。在OOP的世界中,程式都是通過類和介面組織的,使用它們實現程式的核心業務邏輯是十分合適,但是對於實現橫切關註點(跨越應用程式多個模塊的功能需求)則十分吃力,比如日誌記錄、許可權驗證、異常攔截等。

    個人理解:AOP就是將公用功能提取出來,如果以後公用功能的需求發生變化,只需要改動公用模塊的代碼即可,多個調用的地方則不需要改動。所謂面向切麵,就是只關註通用功能,而不關註業務邏輯。它實現的方式一般是通過攔截,比如,項目中一般都有許可權驗證的功能,進入每個頁面前都會驗證當前登錄用戶是否有許可權查看該界面。我們不可能說在每個頁面的初始化方法裡面都去寫這段驗證的代碼,這個時候我們的AOP就派上用場了。AOP的機制是預先定義一組特性,使它具有攔截方法的功能,可以讓你在執行方法之前和之後做你想做的業務,而我們使用的時候只需要在對應的方法或者類定義上面加上某一個特性就好了。

    二、AOP優勢

    1)將通用功能從業務邏輯中抽離出來,可以省略大量的重覆代碼,有利於代碼的操作和維護。

    2)在軟體設計時,抽出通用功能(切麵),有利於軟體設計的模塊化,降低軟體架構的複雜度。也就是說通用的功能都是一個個單獨的模塊,在項目的主業務裡面是看不到這些通用功能的設計代碼的。

    三、AOP應用

    3.1、靜態代理方式

    3.1.1、使用裝飾器模式實現靜態代理

    1)新建一個類:DecoratorAOP.cs

    /// <summary>
    /// 使用裝飾器模式實現靜態代理
    /// </summary>
    public class DecoratorAOP
    {
        /// <summary>
        /// 用戶類
        /// </summary>
        public class User
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Password { get; set; }
        }

        /// <summary>
        /// 用戶註冊介面
        /// </summary>
        public interface IUserProcessor
        {
            void RegUser(User user);
        }

        /// <summary>
        /// 用戶註冊介面實現類
        /// </summary>
        public class UserProcessor : IUserProcessor
        {
            public void RegUser(User user)
            {
                Console.WriteLine($"用戶註冊成功。Name:{user.Name} Password:{user.Password}");
            }
        }

        /// <summary>
        /// 裝飾器模式實現AOP功能
        /// </summary>
        public class UserProcessorDecorator : IUserProcessor
        {
            private IUserProcessor UserProcessor { get; set; }
            public UserProcessorDecorator(IUserProcessor userProcessor)
            {
                UserProcessor = userProcessor;
            }

            public void RegUser(User user)
            {
                PreProceed(user);
                UserProcessor.RegUser(user);
                PostProceed(user);
            }

            public void PreProceed(User user)
            {
                Console.WriteLine("方法執行前");
            }

            public void PostProceed(User user)
            {
                Console.WriteLine("方法執行後");
            }
        }

        /// <summary>
        /// 運行測試
        /// </summary>
        public static void Show()
        {
            User user = new User() { Name = "Hello", Password = "World" };
            IUserProcessor processor = new UserProcessorDecorator(new UserProcessor());
            processor.RegUser(user);
        }
    }
View Code

    2)調用:

        static void Main(string[] args)
        {
            #region 使用裝飾器模式實現靜態代理
            DecoratorAOP.Show();
            Console.Read();
            #endregion
        }
View Code

    3)運行結果如下:

    上面代碼是模擬用戶註冊的例子:註冊信息提交前,需要做一些準備工作,比如數據有效性校驗等;註冊信息提交後,還需要做日誌記錄等。從上面的代碼可以看出,我們通過靜態植入的方式,手動地在執行方法前和執行方法後讓它做一些我們需要的功能。

    3.1.2、使用代理模式實現靜態代理

    1)新建一個類:ProxyAOP.cs

    /// <summary>
    /// 使用代理模式實現靜態代理
    /// </summary>
    public class ProxyAOP
    {
        /// <summary>
        /// 用戶類
        /// </summary>
        public class User
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Password { get; set; }
        }

        /// <summary>
        /// 用戶註冊介面
        /// </summary>
        public interface IUserProcessor
        {
            void RegUser(User user);
        }

        /// <summary>
        /// 用戶註冊介面實現類
        /// </summary>
        public class UserProcessor : IUserProcessor
        {
            public void RegUser(User user)
            {
                Console.WriteLine($"用戶註冊成功。Name:{user.Name} Password:{user.Password}");
            }
        }

        /// <summary>
        /// 代理模式實現AOP功能
        /// </summary>
        public class UserProcessorProxy : IUserProcessor
        {
            private IUserProcessor userProcessor = new UserProcessor();

            public void RegUser(User user)
            {
                PreProceed(user);
                userProcessor.RegUser(user);
                PostProceed(user);
            }

            private void PreProceed(User user)
            {
                Console.WriteLine("方法執行前");
            }

            private void PostProceed(User user)
            {
                Console.WriteLine("方法執行後");
            }
        }

        public static void Show()
        {
            User user = new User() { Name = "Hello", Password = "World" };
            IUserProcessor processor = new UserProcessorProxy();
            processor.RegUser(user);
        }
    }
View Code

    2)調用:

        static void Main(string[] args)
        {
            #region 使用代理模式實現靜態代理
            ProxyAOP.Show();
            Console.Read();
            #endregion
        }
View Code

    3)運行結果如下:

    3.2、動態代理方式

    3.2.1、使用.Net Remoting/RealProxy實現動態代理

    1)新建一個類:RealProxyAOP.cs

    /// <summary>
    /// 使用.Net Remoting/RealProxy實現動態代理
    /// Client - TransparentProxy - RealProxy - Target Object
    /// 局限在業務類必須是繼承自MarshalByRefObject類型
    /// </summary>
    public class RealProxyAOP
    {
        /// <summary>
        /// 用戶類
        /// </summary>
        public class User
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Password { get; set; }
        }

        /// <summary>
        /// 用戶註冊介面
        /// </summary>
        public interface IUserProcessor
        {
            void RegUser(User user);
        }

        /// <summary>
        /// 用戶註冊介面實現類
        /// 必須繼承自MarshalByRefObject父類,否則無法生成。
        /// </summary>
        public class UserProcessor : MarshalByRefObject, IUserProcessor
        {
            public void RegUser(User user)
            {
                Console.WriteLine($"用戶註冊成功。Name:{user.Name} Password:{user.Password}");
            }
        }

        /// <summary>
        /// 真實代理:提供代理的基本功能
        /// </summary>
        public class MyRealProxy<T> : RealProxy
        {
            private T _target;
            public MyRealProxy(T target) : base(typeof(T))
            {
                _target = target;
            }

            public override IMessage Invoke(IMessage msg)
            {
                PreProceed(msg);
                IMethodCallMessage callMessage = (IMethodCallMessage)msg;
                object returnValue = callMessage.MethodBase.Invoke(_target, callMessage.Args);
                PostProceed(msg);
                return new ReturnMessage(returnValue, new object[0], 0, null, callMessage);
            }

            public void PreProceed(IMessage msg)
            {
                Console.WriteLine("方法執行前");
            }

            public void PostProceed(IMessage msg)
            {
                Console.WriteLine("方法執行後");
            }
        }

        /// <summary>
        /// 透明代理:提供實際對象駐留在客戶端空間中的假象
        /// </summary>
        public static class TransparentProxy
        {
            public static T Create<T>()
            {
                T instance = Activator.CreateInstance<T>();
                MyRealProxy<T> realProxy = new MyRealProxy<T>(instance);
                T transparentProxy = (T)realProxy.GetTransparentProxy();
                return transparentProxy;
            }
        }

        /// <summary>
        /// 運行測試
        /// </summary>
        public static void Show()
        {
            User user = new User() { Name = "Hello", Password = "World" };
            UserProcessor processor = TransparentProxy.Create<UserProcessor>();
            processor.RegUser(user);
        }
    }
View Code

    2)調用:

        static void Main(string[] args)
        {
            #region 使用.Net Remoting/RealProxy實現動態代理
            RealProxyAOP.Show();
            Console.Read();
            #endregion
        }
View Code

    3)運行結果如下:

    3.2.2、使用Castle\DynamicProxy實現動態代理

    1)在NuGet中安裝Castle.Core。

    2)新建一個類:CastleProxyAOP.cs

    /// <summary>
    /// 使用Castle\DynamicProxy實現動態代理
    /// 方法必須是虛方法
    /// </summary>
    public class CastleProxyAOP
    {
        /// <summary>
        /// 用戶類
        /// </summary>
        public class User
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Password { get; set; }
        }

        /// <summary>
        /// 用戶註冊介面
        /// </summary>
        public interface IUserProcessor
        {
            void RegUser(User user);
        }

        /// <summary>
        /// 用戶註冊介面實現類
        /// </summary>
        public class UserProcessor : IUserProcessor
        {
            /// <summary>
            /// 必須帶上virtual,否則無效。
            /// </summary>
            /// <param name="user"></param>
            public virtual void RegUser(User user)
            {
                Console.WriteLine($"用戶註冊成功。Name:{user.Name} Password:{user.Password}");
            }
        }

        /// <summary>
        /// 攔截器
        /// </summary>
        public class MyInterceptor : IInterceptor
        {
            public void Intercept(IInvocation invocation)
            {
                PreProceed(invocation);
                invocation.Proceed();
                PostProceed(invocation);
            }
            public void PreProceed(IInvocation invocation)
            {
                Console.WriteLine("方法執行前");
            }

            public void PostProceed(IInvocation invocation)
            {
                Console.WriteLine("方法執行後");
            }
        }

        /// <summary>
        /// 運行測試
        /// </summary>
        public static void Show()
        {
            User user = new User() { Name = "Hello", Password = "World" };
            ProxyGenerator generator = new ProxyGenerator();
            MyInterceptor interceptor = new MyInterceptor();
            UserProcessor userprocessor = generator.CreateClassProxy<UserProcessor>(interceptor);
            userprocessor.RegUser(user);
        }
    }
View Code

    3)調用:

        static void Main(string[] args)
        {
            #region 使用Castle\DynamicProxy實現動態代理
            CastleProxyAOP.Show();
            Console.Read();
            #endregion
        }
View Code

    4)運行結果如下:

    3.2.3、使用EntLib\PIAB Unity實現AOP(非配置)

    1)在NuGet中安裝Unity及Unity.Interception。

    2)新建一個類:UnityAOP.cs

    /// <summary>
    /// 使用EntLib\PIAB Unity實現動態代理(非配置)
    /// </summary>
    public class UnityAOP
    {
        #region 業務
        /// <summary>
        /// 用戶類
        /// </summary>
        public class User
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Password { get; set; }
        }

        /// <summary>
        /// 用戶註冊介面
        /// </summary>
        [ExceptionHandler(Order = 1)]
        [LogHandler(Order = 2)]
        [UserHandler(Order = 3)]
        [AfterLogHandler(Order = 5)]
        public interface IUserProcessor
        {
            void RegUser(User user);
        }

        /// <summary>
        /// 用戶註冊介面實現類
        /// </summary>
        public class UserProcessor : IUserProcessor //可以不繼承MarshalByRefObject類
        {
            public void RegUser(User user)
            {
                Console.WriteLine($"用戶註冊成功。Name:{user.Name} Password:{user.Password}");
            }
        }
        #endregion 業務

        #region 特性
        /// <summary>
        /// 異常處理特性
        /// </summary>
        public class ExceptionHandlerAttribute : HandlerAttribute
        {
            public override ICallHandler CreateHandler(IUnityContainer container)
            {
                return new ExceptionHandler() { Order = Order };
            }
        }

        /// <summary>
        /// 日誌處理特性
        /// </summary>
        public class LogHandlerAttribute : HandlerAttribute
        {
            public override ICallHandler CreateHandler(IUnityContainer container)
            {
                return new LogHandler() { Order = Order };
            }
        }

        /// <summary>
        /// 用戶信息特性
        /// </summary>
        public class UserHandlerAttribute : HandlerAttribute
        {
            public override ICallHandler CreateHandler(IUnityContainer container)
            {
                ICallHandler handler = new UserHandler() { Order = Order };
                return handler;
            }
        }

        /// <summary>
        /// 後續日誌特性
        /// </summary>
        public class AfterLogHandlerAttribute : HandlerAttribute
        {
            public override ICallHandler CreateHandler(IUnityContainer container)
            {
                return new AfterLogHandler() { Order = Order };
            }
        }
        #endregion 特性

        #region 特性對應的行為
        public class ExceptionHandler : ICallHandler
        {
            public int Order { get; set; }
            public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
            {
                IMethodReturn methodReturn = getNext()(input, getNext);

                if (methodReturn.Exception == null)
                {
                    Console.WriteLine("ExceptionHandler:沒有異常");
                }
                else
                {
                    Console.WriteLine($"ExceptionHandler:出現異常:{methodReturn.Exception.Message}");
                }

                return methodReturn;
            }
        }

        public class LogHandler : ICallHandler
        {
            public int Order { get; set; }
            public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
            {
                User user = input.Inputs[0] as User;
                string message = string.Format($"Name:{user.Name} Password:{user.Password}");
                Console.WriteLine($"LogHandler:日誌已記錄。Message:{message}");

                IMethodReturn methodReturn = getNext()(input, getNext);
                return methodReturn;
            }
        }

        public class UserHandler : ICallHandler
        {
            public int Order { get; set; }
            public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
            {
                User user = input.Inputs[0] as User;

                if (user.Password.Length < 10)
                {
                    return input.CreateExceptionMethodReturn(new Exception("UserHandler:密碼長度不能小於10位"));
                }

                //getNext()(input, getNext):委托後的委托,即多重委托。
                IMethodReturn methodReturn = getNext()(input, getNext);
                return methodReturn;
            }
        }

        public class AfterLogHandler : ICallHandler
        {
            public int Order { get; set; }
            public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
            {
                IMethodReturn methodReturn = getNext()(input, getNext);
                Console.WriteLine($"AfterLogHandler:方法執行結果--{methodReturn.ReturnValue}");
                Console.WriteLine("AfterLogHandler:方法執行後");

                return methodReturn;
            }
        }
        #endregion 特性對應的行為

        /// <summary>
        /// 運行測試
        /// </summary>
        public static void Show()
        {
            User user = new User() { Name = "Hello", Password = "HelloWorld" };

            IUnityContainer container = new UnityContainer();           //聲明一個容器
            container.AddNewExtension<Interception>()
                .RegisterType<IUserProcessor, UserProcessor>(new Interceptor<TransparentProxyInterceptor>(), new InterceptionBehavior<PolicyInjectionBehavior>());  //顯式攔截
            IUserProcessor processor = container.Resolve<IUserProcessor>();
            processor.RegUser(user);                                    //調用
        }
    }
View Code

    3)調用:

        static void Main(string[] args)
        {
            #region 使用EntLib\PIAB Unity實現動態代理(非配置)
            UnityAOP.Show();
            Console.Read();
            #endregion
        }
View Code

    4)運行結果如下:

    3.2.4、使用EntLib\PIAB Unity實現AOP(帶配置)

    1)繼續在NuGet中安裝Unity.Configuration、Unity.Interception.Configuration及Newtonsoft.Json。

    2)分別建立以下類:

    /// <summary>
    /// 用戶類
    /// </summary>
    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Password { get; set; }
    }
Entity.cs(用戶實體類)
    /// <summary>
    /// 用戶註冊介面
    /// </summary>
    public interface IUserProcessor
    {
        void RegUser(User user);
    }
IUserProcessor.cs(用戶註冊介面)
    /// <summary>
    /// 用戶註冊介面實現類
    /// </summary>
    public class UserProcessor : IUserProcessor
    {
        public void RegUser(User user)
        {
            Console.WriteLine($"用戶註冊成功。Name:{user.Name} Password:{user.Password}");
        }
    }
UserProcessor.cs(用戶註冊介面實現類)
    /// <summary>
    /// 使用EntLib\PIAB Unity實現動態代理(帶配置)
    /// </summary>
    public class UnityConfigAOP
    {
        public static void Show()
        {
            User user = new User() { Name = "Hello", Password = "HelloWorld" };

            //配置UnityContainer
            IUnityContainer container = new UnityContainer();
            ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap
            {
                ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + @"UnityConfigAOP\Unity.Config")
            };
            Configuration configuration =	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 題目: 代碼及思路: #include <stdio.h> #include <string.h> int main() { //以字元串的形式接受用戶輸入的數字 char str[1000]; //定義一個統計數組 int nums1[10] = {0}; scanf("%s", str); // ...
  • 什麼是微服務?什麼是SpringCloud? 微服務是一種架構的模式,它提倡將一個應用程式劃分成很多個微小的服務,服務與服務之間相互協調、相互配合。每個服務運行都是一個獨立的進程,服務與服務之間採用輕量級的通訊機制相互溝通。簡單的來說就是將一個龐大的複雜的單體應用進行劃分成n多個微小的服務(一個服務 ...
  • 一、Servlet簡介 1.1、Servlet是sun公司提供的一門用於開發動態web資源的技術,Servlet屬於動態資源。 1.2、Servlet(Server Applet)是Java Servlet的簡稱,Servlet就是一個運行在伺服器端的Java類。 1.3、Servlet就是Java ...
  • 經過前期大量的學習與準備,我們重要要開始寫第一個真正意義上的爬蟲了。本次我們要爬取的網站是:百度貼吧,一個非常適合新人練手的地方,那麼讓我們開始吧。 本次要爬的貼吧是<< 西部世界 >>,西部世界是我一直很喜歡的一部美劇,平時有空也會去看看吧友們都在聊些什麼。所以這次選取這個吧來作為實驗材料。註意: ...
  • 題目:點此 描述 小Hi和小Ho準備國慶期間去A國旅游。A國的城際交通比較有特色:它共有n座城市(編號1-n);城市之間恰好有n-1條公路相連,形成一個樹形公路網。小Hi計劃從A國首都(1號城市)出發,自駕遍歷所有城市,並且經過每一條公路恰好兩次——來回各一次——這樣公路兩旁的景色都不會錯過。 令小 ...
  • 依賴 <dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>5.8.0</version> </dependency> 生產者 public class Producer ...
  • Trigger 就是觸發器的意思,用來指定什麼時間開始觸發,觸發多少次,每隔多久觸發一次 SimpleTrigger 可以方便的實現一系列的觸發機制。 1.下一個8秒的倍數開始運行: public class SimpleTriggerDemo { public static void main(S ...
  • 最近工作比較忙,未能及時更新內容,敬請瞭解!!! 對於可視化樹的分析引出了幾個有趣問題。例如,控制項如何從邏輯樹表示擴張成可視化樹表示? 每個控制項都有一個內置的方法,用於確定如何渲染控制項(作為一組更基礎的元素)。該方法稱為控制項模板(control template),是用XAML標記塊定義的。 下麵是 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...