C#/.NET Unity靜態實現AOP功能——實際案例Demo程式碼
阿新 • • 發佈:2019-01-09
C# Unity依賴注入利用Attribute實現AOP功能
在做專案時,常常要對某個功能進行擴充套件,我們一般都是利用OOP的思想, 在原有的功能上進行擴充套件。
如果能用AOP思想去擴充套件,會使程式碼的整體框架更加穩定,我推薦Unity框架,接下來介紹一下如何使用。
1. 首先通過NuGet新增相關依賴
需要Unity和Unity.Interception
!!重要!!注意!!版本不要選太新版,Unity選5.6.0以前的,Interception也選5.2.0左右的即可,新版使用該案例會出現一些問題,如有解決方法請在評論指出
2. 新增namespace
using Unity;
using Unity.Interception.ContainerIntegration;
using Unity.Interception.Interceptors.InstanceInterceptors.InterfaceInterception;
using Unity.Interception.PolicyInjection.Pipeline;
using Unity.Interception.PolicyInjection.Policies;
3. 開始使用EntLib\PIAB Unity 實現動態代理
3.1 先寫好相關特性Attribute,必須繼承自HandlerAttribute
#region 特性 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 AfterLogHandlerAttribute : HandlerAttribute { public override ICallHandler CreateHandler(IUnityContainer container) { return new AfterLogHandler() { Order = this.Order }; } } #endregion 特性
3.2 再寫特性對應的行為
注[1]Order:是特性執行的順序,具體看後面的操作例項
注[2]getNext:執行下一個函式先,如果getNext在前面,那麼就是主程式執行完再執行這個特性行為(需要注意Order順序會反過來),否則就是在特性前(Order順序正常排序)
注[3]input:輸入的引數,input[0]是第一個引數…以此類推
#region 特性對應的行為
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()(input, getNext); //getNext.Invoke().Invoke(input, getNext);
//Console.WriteLine("已完成操作");
return methodReturn;
}
}
public class LogHandler : ICallHandler
{
public int Order { get; set; }
/// <summary>
///
/// </summary>
/// <param name="input">方法呼叫的引數列表</param>
/// <param name="getNext"></param>
/// <returns></returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
User user = input.Inputs[0] as User;
string message = $"RegUser:Username:{user.Name},Password:{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($"異常:{methodReturn.Exception.Message}");
}
return methodReturn;
}
}
public class AfterLogHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
IMethodReturn methodReturn = getNext()(input, 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},計算結果{2}", message, DateTime.Now, methodReturn.ReturnValue);
return methodReturn;
}
}
#endregion 特性對應的行為
3.3 最後寫相關的業務(函式方法/功能)
注[1]Order:這裡特性的執行順序是按照Order從小到大排的
注[2]DIP原則:這裡最好使用依賴倒置原則來寫,操作抽象會使程式碼更加穩定
#region 業務
[UserHandlerAttribute(Order = 1)]
[LogHandlerAttribute(Order = 2)]
[ExceptionHandlerAttribute(Order = 3)]
[AfterLogHandlerAttribute(Order = 4)]
public interface IUserProcessor
{
void RegUser(User user);
User GetUser(User user);
}
public class UserProcessor : IUserProcessor
{
public void RegUser(User user)
{
Console.WriteLine("使用者已註冊。");
//throw new Exception("11");
}
public User GetUser(User user)
{
return user;
}
}
#endregion 業務
4. 具體操作實現
注[1]斷點:在下面註釋需要打斷點的那裡打斷點檢視具體執行順序,以便理解
public static void Show()
{
User user = new User()
{
Name = "Eleven",
Password = "12345678957576"
};
{
UserProcessor processor = new UserProcessor();
processor.RegUser(user);
Console.WriteLine("*********************");
}
{
IUnityContainer container = new UnityContainer();//宣告一個容器
container.RegisterType<IUserProcessor, UserProcessor>();//宣告UnityContainer並註冊IUserProcessor
IUserProcessor processor = container.Resolve<IUserProcessor>();
processor.RegUser(user);//沒有AOP的,可在此打個斷點F11進入
//配置AOP,固定套路
container.AddNewExtension<Interception>()
.Configure<Interception>()
.SetInterceptorFor<IUserProcessor>(new InterfaceInterceptor());
IUserProcessor userprocessor = container.Resolve<IUserProcessor>();//重新例項化
Console.WriteLine("********************");
userprocessor.RegUser(user);//有AOP的,可在此打個斷點F11進入
userprocessor.GetUser(user);//有AOP的,可在此打個斷點F11進入
}
}