1. 程式人生 > >C# Unity依賴註入利用Attribute實現AOP功能

C# Unity依賴註入利用Attribute實現AOP功能

stat 這就是 sin fig 相對 成了 開始 不難 time

使用場景?

很多時候, 我們定義一個功能, 當我們要對這個功能進行擴展的時候, 按照常規的思路, 我們一般都是利用OOP的思想, 在原有的功能上進行擴展。

那麽有沒有一種東西, 可以實現當我們需要擴展這個功能的時候, 在不修改原來的功能代碼的情況下實現, 這就是下面要說的到Unity。

1.準備工作

為項目添加NuGet包, 搜索Unity並且安裝。

技術分享圖片

在使用的項目中添加Unity的相關引用

using Microsoft.Practices.Unity.InterceptionExtension;
using Microsoft.Practices.Unity;

2.假設場景

剛才上面說道, Unity可實現在不修改原功能的情況下, 添加額外的擴展功能。

在我們的實際開發中, 也可以舉個簡單的例子。

當我們去做一個用戶註冊的功能, 最初的版本是完成了基本的註冊功能, 後來我們需要擴展了, 給他加上註冊校驗, 日誌處理, 和異常捕捉的幾個功能, 那麽接下來就演示, 如何用Unity給功能擴展。

3.如何使用

首先, 我們定義好一個最原始的註冊功能

        public static void Show()
        {
            User user = new User()
            {
                Name = "Eleven",
                Password 
= "123123123123" };
IUserProcessor porcessor = new UserProcessor();
porcessor.RegUser(user); //簡單的用戶註冊
}

        public interface IUserProcessor
        {
            void RegUser(User user);
        }

        public class UserProcessor : IUserProcessor//MarshalByRefObject,
{ public void RegUser(User user) { Console.WriteLine("註冊"); } }

接下來, 我們要對這個註冊進行擴展了, 添加註冊校驗, 日誌處理, 和異常捕捉的幾個功能。

1.先定義3個特性與對應的特性行為實現, 分別是註冊, 日誌, 和異常。

       public class UserHandlerAttribute : HandlerAttribute  //註冊校驗
        {
            public override ICallHandler CreateHandler(IUnityContainer container)
            {
                ICallHandler handler = new UserHandler() { Order = this.Order };
                return handler;
            }
        }

        public class LogHandlerAttribute : HandlerAttribute   //日誌處理
        {
            public override ICallHandler CreateHandler(IUnityContainer container)
            {
                return new LogHandler() { Order = this.Order };
            }
        }

        public class ExceptionHandlerAttribute : HandlerAttribute  //異常處理
        {
            public override ICallHandler CreateHandler(IUnityContainer container)
            {
                return new ExceptionHandler() { Order = this.Order };
            }
        }

對應的每個特性的實現行為, 分別實現 註冊校驗, 日誌記錄, 與 異常處理

        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("密碼長度不能小於10位"));
                }
                Console.WriteLine("參數檢測無誤");
                
                IMethodReturn methodReturn = getNext.Invoke().Invoke(input, getNext);
                
                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("RegUser:Username:{0},Password:{1}", user.Name, user.Password);
                Console.WriteLine("日誌已記錄,Message:{0},Ctime:{1}", message, DateTime.Now);
                return getNext()(input, getNext);
            }
        }


        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("無異常");
                }
                else
                {
                    Console.WriteLine("異常:{0}", methodReturn.Exception.Message);
                }
                return methodReturn;
            }
        }

按照現在思路, 我們要把這上面寫好的幾個功能添加在原來的註冊功能上, 首先, 我們回到最開始定義接口的地方, 給接口添加我們定義按的3個特性

        [UserHandlerAttribute(Order = 1)] //註冊校驗
        [LogHandlerAttribute(Order = 2)]  //日誌處理
        [ExceptionHandlerAttribute(Order = 3)] //遺產處理
        public interface IUserProcessor
        {
            void RegUser(User user);
        }

//PS: 在上面的特性聲明中, 每個對應的Order 這個屬於排序, 相對於一個行為的執行順序, 這個內部是Unity的一個實現, 所以我們使用的過程中只需要聲明好標量即可。

然後, 我們在定義好的註冊方法中, 首先聲明一個Unity容器UnityContainer , 然後註冊其上面的接口 IUserProcessor, 最後調用其接口的註冊方法。

            //聲明一個容器
            IUnityContainer container = new UnityContainer();

            //聲明UnityContainer並註冊IUserProcessor
            container.RegisterType<IUserProcessor, UserProcessor>();

            container.AddNewExtension<Interception>().Configure<Interception>()
                .SetInterceptorFor<IUserProcessor>(new InterfaceInterceptor());
            IUserProcessor userprocessor = container.Resolve<IUserProcessor>();
            userprocessor.RegUser(user); //調用註冊方法。

最後, 我們看一下實際效果, 很輕松的實現了用於註冊時候擴展其他更多的行為

技術分享圖片

小結:

不難發現, Unity的實現 主要以在接口上定義的特性與實現行為 與其內部Unity容器的結合 實現的AOP功能。

因為上面是屬於靜態的寫法, 便於學習, 真正的實現AOP可動態配置, 在IOC裏會有詳細的介紹。

C# Unity依賴註入利用Attribute實現AOP功能