AOP為Aspect Oriented Programming的縮寫,意為:面向切面編程,通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。AOP是OOP的延續,是軟件開發中的一個熱點……是函數式編程的一種衍生范型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。
動態代理是實現AOP的一種方式,即在開發過程中我們不需要處理切面中(日志等)的工作,而是在運行時,通過動態代理來自動完成。Castle DynamicProxy是一個實現動態代理的框架,被很多優秀的項目用來實現AOP編程,EF Core、Autofac等。
為業務類添加AOP攔截器
- /// <summary>
- /// 為業務類添加AOP攔截器。
- /// </summary>
- public class InterceptorAttribute:PlutoStudio.Aop.InterceptorAttribute
- {
- /// <summary>
- /// 攔截方法的執行,如果當前方法有攔截處理器,則執行處理器。
- /// </summary>
- /// <param name="invocation">被攔截的調用目標對象</param>
- public override void Intercept(IInvocation invocation)
- {
- var method = invocation.Method;
- var processors = method.GetCustomAttributes(typeof(IInterceptorProcessor),true).Cast<IInterceptorProcessor>().ToList();
- processors.ForEach(p => PlutoStudio.MefContainer.Container.ComposeParts(p));
- if (processors.Count>0)
- {
- processors.ForEach(p => p.PreProcess(invocation));
- try
- {
- invocation.Proceed();
- processors.ForEach(p => p.PostProcess(invocation, null));
- }
- catch (Exception ex)
- {
- processors.ForEach(p => p.PostProcess(invocation, ex));
- throw;
- }
- }
- else
- {
- invocation.Proceed();
- }
- }
- }
- /// <summary>
- /// 攔截器處理器接口。
- /// </summary>
- public interface IInterceptorProcessor
- {
- /// <summary>
- /// 攔截器處理方法,在目標方法執行前執行。
- /// </summary>
- /// <param name="invocation">攔截的目標對象</param>
- void PreProcess(IInvocation invocation);
- /// <summary>
- /// 攔截器處理方法,在目標方法執行后執行。
- /// </summary>
- /// <param name="invocation">攔截的目標對象</param>
- /// <param name="ex">目標方法的異常</param>
- void PostProcess(IInvocation invocation,Exception ex);
- }
日志處理器
可以將目標方法的信息保存到日志系統中
- /// <summary>
- /// 日志處理器,可以將目標方法的信息保存到日志系統中。
- /// </summary>
- [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
- public class LogAttribute : Attribute, IInterceptorProcessor
- {
- [Import(AllowDefault = true)]
- public ILog Log { get; set; }
- /// <summary>
- /// 在目標方法執行完成后執行,這里會記錄目標方法的相關信息并寫入日志系統。
- /// </summary>
- /// <param name="invocation"></param>
- /// <param name="ex"></param>
- public void PostProcess(IInvocation invocation, Exception ex)
- {
- if (Log != null)
- {
- var @class = invocation.TargetType.FullName;
- var method = invocation.Method.Name;
- var parameterNames = invocation.Method.GetParameters().Select(p => p.Name).ToList();
- var args = invocation.Arguments;
- var parameters = new Dictionary<string, object>();
- for (int i = 0; i < parameterNames.Count; i++)
- {
- parameters.Add(parameterNames[i], args[i]);
- }
- var returnValue = invocation.ReturnValue;
- var stackTrace = new StackTrace(true);
- var stacks = stackTrace.GetFrames();
- var stack = stacks.SkipWhile(i => i.GetMethod().Name != invocation.Method.Name).Select(GetStack);
- var log = new TraceLog
- {
- Class = @class,
- Method = method,
- Parameter = parameters,
- ReturnValue = returnValue,
- Strack = stack,
- Exception = ex,
- };
- Log.Custom(log);
- }
- }
- private object GetStack(StackFrame frame)
- {
- var method = frame.GetMethod();
- var type = method.ReflectedType;
- if (type.FullName.StartsWith("Castle.Proxies"))
- {
- type = type.BaseType;
- }
- return new
- {
- Method = method.Name,
- Type = type.FullName,
- File = frame.GetFileName(),
- Line = frame.GetFileLineNumber(),
- };
- }
- public void PreProcess(IInvocation invocation)
- {
- }
- }
- /// <summary>
- /// 系統跟蹤日志,由<see cref="LogAttribute"/>生成。
- /// </summary>
- public class TraceLog
- {
- /// <summary>
- /// 當前日志記錄的目標類。
- /// </summary>
- public string Class { get; internal set; }
- /// <summary>
- /// 當前日志跟蹤到的異常。
- /// </summary>
- public Exception Exception { get; internal set; }
- /// <summary>
- /// 當前日志記錄的目標方法。
- /// </summary>
- public string Method { get; internal set; }
- /// <summary>
- /// 當前日志記錄的目標方法的參數。
- /// </summary>
- public Dictionary<string, object> Parameter { get; internal set; }
- /// <summary>
- /// 當前日志記錄的目標方法的返回值。
- /// </summary>
- public object ReturnValue { get; internal set; }
- /// <summary>
- /// 當前日志記錄的目標方法的調用棧。
- /// </summary>
- public IEnumerable<object> Strack { get; internal set; }
- }
原文鏈接:https://mp.weixin.qq.com/s/CgnC5D4qeBKSsrqzMV4p-w