首页 > 编程语言 >利用AspectInjector实现AOP篡改方法返回值

利用AspectInjector实现AOP篡改方法返回值

时间:2023-08-06 19:33:23浏览次数:35  
标签:args object AspectInjector returnType eventArgs AOP var 返回值 public

AspectInjector

一个开源的轻量级AOP框架,满足大多数场景。但由于该框架注入异步方法不是很方便,故记录下解决方案。

封装通用基类

public abstract class BaseUniversalWrapperAspect
    {
        private delegate object Method(object[] args);
        private delegate object Wrapper(Func<object[], object> target, object[] args);
        private delegate object Handler(Func<object[], object> next, object[] args, AspectEventArgs eventArgs);

        private static readonly ConcurrentDictionary<(MethodBase, Type), Lazy<Handler>> _delegateCache = new ConcurrentDictionary<(MethodBase, Type), Lazy<Handler>>();

        private static readonly MethodInfo _asyncGenericHandler =
            typeof(BaseUniversalWrapperAttribute).GetMethod(nameof(BaseUniversalWrapperAttribute.WrapAsync), BindingFlags.NonPublic | BindingFlags.Instance);

        private static readonly MethodInfo _syncGenericHandler =
            typeof(BaseUniversalWrapperAttribute).GetMethod(nameof(BaseUniversalWrapperAttribute.WrapSync), BindingFlags.NonPublic | BindingFlags.Instance);

        private static readonly Type _voidTaskResult = Type.GetType("System.Threading.Tasks.VoidTaskResult");

        protected object BaseHandle(
            object instance,
            Type type,
            MethodBase method,
            Func<object[], object> target,
            string name,
            object[] args,
            Type returnType,
            Attribute[] triggers)
        {
            var eventArgs = new AspectEventArgs
            {
                Instance = instance,
                Type = type,
                Method = method,
                Name = name,
                Args = args,
                ReturnType = returnType,
                Triggers = triggers
            };

            var wrappers = triggers.OfType<BaseUniversalWrapperAttribute>().ToArray();

            var handler = GetMethodHandler(method, returnType, wrappers);
            return handler(target, args, eventArgs);
        }

        private Handler CreateMethodHandler(Type returnType, IReadOnlyList<BaseUniversalWrapperAttribute> wrappers)
        {
            var targetParam = Expression.Parameter(typeof(Func<object[], object>), "orig");
            var eventArgsParam = Expression.Parameter(typeof(AspectEventArgs), "event");

            MethodInfo wrapperMethod;

            if (typeof(Task).IsAssignableFrom(returnType))
            {
                var taskType = returnType.IsConstructedGenericType ? returnType.GenericTypeArguments[0] : _voidTaskResult;
                returnType = typeof(Task<>).MakeGenericType(new[] { taskType });

                wrapperMethod = _asyncGenericHandler.MakeGenericMethod(new[] { taskType });
            }
            else
            {
                if (returnType == typeof(void))
                    returnType = typeof(object);

                wrapperMethod = _syncGenericHandler.MakeGenericMethod(new[] { returnType });
            }

            var converArgs = Expression.Parameter(typeof(object[]), "args");
            var next = Expression.Lambda(Expression.Convert(Expression.Invoke(targetParam, converArgs), returnType), converArgs);

            foreach (var wrapper in wrappers)
            {
                var argsParam = Expression.Parameter(typeof(object[]), "args");
                next = Expression.Lambda(Expression.Call(Expression.Constant(wrapper), wrapperMethod, next, argsParam, eventArgsParam), argsParam);
            }

            var orig_args = Expression.Parameter(typeof(object[]), "orig_args");
            var handler = Expression.Lambda<Handler>(Expression.Convert(Expression.Invoke(next, orig_args), typeof(object)), targetParam, orig_args, eventArgsParam);

            var handlerCompiled = handler.Compile();

            return handlerCompiled;
        }

        private Handler GetMethodHandler(MethodBase method, Type returnType, IReadOnlyList<BaseUniversalWrapperAttribute> wrappers)
        {
            var lazyHandler = _delegateCache.GetOrAdd((method, returnType), _ => new Lazy<Handler>(() => CreateMethodHandler(returnType, wrappers)));
            return lazyHandler.Value;
        }
    }
public abstract class BaseUniversalWrapperAttribute : Attribute
    {
        protected internal virtual T WrapSync<T>(Func<object[], T> target, object[] args, AspectEventArgs eventArgs)
        {
            return target(args);
        }
        protected internal virtual Task<T> WrapAsync<T>(Func<object[], Task<T>> target, object[] args, AspectEventArgs eventArgs)
        {
            return target(args);
        }
    }
public abstract class BaseMethodPointsAspectAttribute : BaseUniversalWrapperAttribute
    {
        protected internal sealed override T WrapSync<T>(Func<object[], T> target, object[] args, AspectEventArgs eventArgs)
        {
            OnBefore(eventArgs);

            try
            {
                var result = base.WrapSync(target, args, eventArgs);
                OnAfter(eventArgs);

                return result;
            }
            catch (Exception exception)
            {
                return OnException<T>(eventArgs, exception);
            }
        }

        protected internal sealed override async Task<T> WrapAsync<T>(Func<object[], Task<T>> target, object[] args, AspectEventArgs eventArgs)
        {
            OnBefore(eventArgs);

            try
            {
                var result = await target(args);
                OnAfter(eventArgs);

                return result;
            }
            catch (Exception exception)
            {
                return OnException<T>(eventArgs, exception);
            }
        }

        protected virtual void OnBefore(AspectEventArgs eventArgs)
        {
        }

        protected virtual void OnAfter(AspectEventArgs eventArgs)
        {
        }

        protected virtual T OnException<T>(AspectEventArgs eventArgs, Exception exception)
        {
            throw exception;
        }
    }
public class AspectEventArgs : EventArgs
    {
        public object Instance { get; internal set; }
        public Type Type { get; internal set; }
        public MethodBase Method { get; internal set; }
        public string Name { get; internal set; }
        public IReadOnlyList<object> Args { get; internal set; }
        public Type ReturnType { get; internal set; }
        public Attribute[] Triggers { get; internal set; }
    }

自定义切面类

用于限制参数长度,不符合条件的传参将修改返回值为错误信息。

 [Aspect(Scope.Global)]
    public class CommandLengthLimitAspect : BaseUniversalWrapperAspect
    {
        [Advice(Kind.Around, Targets = Target.Method)]
        public object Handle(
            [Argument(Source.Instance)] object instance,
            [Argument(Source.Type)] Type type,
            [Argument(Source.Metadata)] MethodBase method,
            [Argument(Source.Target)] Func<object[], object> target,
            [Argument(Source.Name)] string name,
            [Argument(Source.Arguments)] object[] args,
            [Argument(Source.ReturnType)] Type returnType,
            [Argument(Source.Triggers)] Attribute[] triggers)
        {
            var trigger = triggers.OfType<CommandLengthLimitAttribute>().First();
            var parameters = args[0] as List<string>;

            if (parameters is not null && !trigger.LimitLengths.Contains(parameters.Count))
            {
                Func<object[], object> func = GetError;
                return BaseHandle(instance, type, method, func, nameof(GetError), null, returnType, triggers);
            }

            return BaseHandle(instance, type, method, target, name, args, returnType, triggers);
        }

        private async Task<string> GetError(object obj)
        {
            await Task.CompletedTask;
            return "错啦~";
        }
    }

自定义特性

[Injection(typeof(CommandLengthLimitAspect), Inherited = true)]
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public class CommandLengthLimitAttribute : BaseMethodPointsAspectAttribute
    {
        public int[] LimitLengths { get; }
        public CommandLengthLimitAttribute(params int[] limitLengths) => LimitLengths = limitLengths;

    }

使用示例

commands长度不为1,Todo 方法返回的string结果将被篡改为错误信息。

[CommandLengthLimit(1)]
public async Task<string> Todo(List<string> commands)
{
    // todo..
}

标签:args,object,AspectInjector,returnType,eventArgs,AOP,var,返回值,public
From: https://www.cnblogs.com/1gcat/p/17609804.html

相关文章

  • day125-aop
    aop简介AOP(AspectOrientedProgramming)是一种设计思想,是软件设计领域中的面向切面编程,它是面向对象编程的一种补充和完善,它以通过预编译方式和运行期动态代理方式实现在不修改源代码的情况下给程序动态统一添加额外功能的一种技术。相关术语横切关注点从每个方法中抽取......
  • 前端学习笔记202306学习笔记第四十二天-async函数的返回值2
         ......
  • 前端学习笔记202306学习笔记第四十二天-promise-then的返回值3
       ......
  • 前端学习笔记202306学习笔记第四十二天-promise-then的返回值1
     ......
  • Spring Boot 中的 AOP 实践
    在SpringBoot中使用AOP(面向切面编程)可以帮助您在应用程序中更优雅地处理横切关注点,如日志、事务管理和安全性。本文将深入探讨如何在SpringBoot中使用AOP,以及如何创建自定义切面来实现特定功能。1.什么是AOP?AOP是一种编程范式,它允许您将横切关注点(如日志、安全性、事务......
  • AOP详解
    1:AOP:AOP为AspectOrientedProgramming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。它提倡的是针对同一类问题的统一处理,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提......
  • 看一家头部实干派互娱公司如何玩转DataOps?
    DataOps的概念自首次被提出至今已有8年,并在2018年被Gartner纳入数据管理技术成熟度曲线。从实施上看,当下DataOps仍处在发展初期,鲜少企业或团队能据此真正沉淀一套方法论或技术产品的体系。不过,随着越来越多的企业开启DataOps实践,相信令人“雾里看花”的DataOps方法体系也会逐渐明朗......
  • Asp.net Web Api .net6 Controller返回值总结
    1、特定的类型最基本的操作返回基元或复杂数据类型,例如, string 或自定义对象。请参考以下操作,该操作返回自定义 Product 对象的集合:[HttpGet]publicTask<List<Product>>Get()=>_productContext.Products.OrderBy(p=>p.Name).ToListAsync();2、返回IEnumer......
  • 白鲸调度系统助力国内头部券商打造国产信创化 DataOps 平台
    导读国内某头部券商是国内排名前三的全国性大型综合证券公司。作为证券行业领头羊之一,该券商一直高度重视核心系统的自主可控以及网络信息安全。早些时候,其已经完成了信创化数据库改造和OA系统适配,接下来的当务之急是完成数据能力平台的信创化改造。随着该券商近年来数据中台的发......
  • 白鲸调度系统助力国内头部券商打造国产信创化 DataOps 平台
    导读国内某头部券商是国内排名前三的全国性大型综合证券公司。作为证券行业领头羊之一,该券商一直高度重视核心系统的自主可控以及网络信息安全。早些时候,其已经完成了信创化数据库改造和OA系统适配,接下来的当务之急是完成数据能力平台的信创化改造。随着该券商近年来数据中台的......