文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

.NET Core 使用委托实现动态流程组装的思路详解

2024-04-02 19:55

关注

引言

在看.NET Core 源码的管道模型中间件(Middleware)部分,觉得这个流程组装,思路挺好的,于是就分享给大家。本次代码实现就直接我之前写的动态代理实现AOP的基础上改的,就不另起炉灶了,主要思路就是运用委托。对委托不理解的可留言,我写一篇委托的常规使用方式,以及底层原理(编译器)的文章

没看过上一章的,我这里大家给贴一下地址:.NET Core 实现动态代理做AOP(面向切面编程)

接下来进入正题

1.定义接口IInterceptor

定义好我们AOP需要实现的接口,不同职责可以定义不同接口,大家根据实际情况划分

 internal interface IInterceptor
    {
    }
    internal interface IInterceptorAction : IInterceptor
    {
        /// <summary>
        /// 执行之前
        /// </summary>
        /// <param name="args">参数</param>
        void AfterAction(object?[]? args);
        /// <summary>
        /// 执行之后
        /// </summary>
        /// <param name="args">参数</param>
        /// <param name="result">结果</param>
        void BeforeAction(object?[]? args, object? result);
    }

2.定义特性

这里只定义一个基类特性类,继承标记接口,用于设置共通配置,且利于后面反射查找

 [AttributeUsage(AttributeTargets.Class)]
    internal class BaseInterceptAttribute : Attribute, IInterceptor
    {
    }

3.编写生成代理类的逻辑

只需要继承.NET CORE 原生DispatchProxy类,重写相关业务代码

3.1 编写创建代理方法

编写一个我们自己的Create方法(),这两个参数为了后面调用目标类储备的,方法实现就只需要调用DispatchProxy类的Create()

internal class DynamicProxy<T> : DispatchProxy
    {
        public T Decorated { get; set; }//目标类
        public IEnumerable<IInterceptorAction> Interceptors { get; set; }  // AOP动作
        /// <summary>
        /// 创建代理实例
        /// </summary>
        /// <param name="decorated">代理的接口类型</param>
        /// <param name="afterAction">方法执行前执行的事件</param>
        /// <param name="beforeAction">方法执行后执行的事件</param>
        /// <returns></returns>
        public T Create(T decorated, IEnumerable<IInterceptor> interceptors)
        {
            object proxy = Create<T, DynamicProxy<T>>(); // 调用DispatchProxy 的Create  创建一个代理实例
            DynamicProxy<T> proxyDecorator = (DynamicProxy<T>)proxy;
            proxyDecorator.Decorated = decorated;
            proxyDecorator.Interceptors = interceptors.Where(c=>c.GetType().GetInterface(typeof(IInterceptorAction).Name) == typeof(IInterceptorAction)).Select(c=>c as IInterceptorAction);
            return (T)proxy;
        }

3.2 重写Invoke方法

这个就是需要实现我们自己的业务了,大家看注释应该就能看懂个大概了,目前这里只处理了IInterceptorAction接口逻辑,比如异常、异步等等,自己可按需实现。而流程组装的精髓就三步

1.不直接去执行targetMethod.Invoke(),而是把它放到委托里面。

2.定义AssembleAction()方法来组装流程,方法里面也不执行方法,也是返回一个执行方法的委托。

3.循环事先在Create()方法存储的特性实例,调用AssembleAction()方法组装流程,这样就达到俄罗斯套娃的效果了。


protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
        {
            Exception exception = null;//由委托捕获变量,用来存储异常
            Func<object?[]?, object?> action = (args) =>
            {
                try
                {
                    return targetMethod?.Invoke(Decorated, args);
                }
                catch (Exception ex)//捕获异常,不影响AOP继续执行
                {
                    exception = ex;
                }
                return null;
            };
            //进行倒序,使其按照由外置内的流程执行
            foreach (var c in Interceptors.Reverse())
            {
                action = AssembleAction(action, c);
            }
            //执行组装好的流程
            var result = action?.Invoke(args);
            //如果方法有异常抛出异常
            if (exception != null)
            {
                throw exception;
            }
            return result;
        }
        private Func<object?[]?, object?>? AssembleAction(Func<object?[]?, object?>? action, IInterceptorAction c)
        {
            return (args) =>
            {
                //执行之前的动作
                AfterAction(c.AfterAction, args);
                var result = action?.Invoke(args);
                //执行之后的动作
                BeforeAction(c.BeforeAction, args, result);
                return result;
            };
        }
        private void AfterAction(Action<object?[]?> action, object?[]? args)
        {
            try
            {
                action(args);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"执行之前异常:{ex.Message},{ex.StackTrace}");
            }
        }
        private void BeforeAction(Action<object?[]?, object?> action, object?[]? args, object? result)
        {
            try
            {
                action(args, result);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"执行之后异常:{ex.Message},{ex.StackTrace}");
            }
        }
    }

4.定义一个工厂

工厂用于专门来为我们创建代理类,逻辑很简单,后续大家也可以按需编写,目前逻辑就是利用反射获取目标类的特性,把参数组装起来。

internal class ProxyFactory
    {
        /// <summary>
        /// 创建代理实例
        /// </summary>
        /// <param name="decorated">代理的接口类型</param>
        /// <returns></returns>
        public static T Create<T>()
        {
            var decorated = ServiceHelp.GetService<T>();
            var type = decorated.GetType();
            var interceptAttribut = type.GetCustomAttributes<BaseInterceptAttribute>();
            //创建代理类
            var proxy = new DynamicProxy<T>().Create(decorated, interceptAttribut);
            return proxy;
        }
    }

5.定义ServiceHelp

这个是为了使得我们全局只用一个作用域的IOC容器

public static class ServiceHelp
    {
        public static IServiceProvider? serviceProvider { get; set; }
        public static void BuildServiceProvider(IServiceCollection serviceCollection)
        {
            //构建容器
            serviceProvider = serviceCollection.BuildServiceProvider();
        }
        public static T GetService<T>(Type serviceType)
        {
            return (T)serviceProvider.GetService(serviceType);
        }
        public static T GetService<T>()
        {
            return serviceProvider.GetService<T>();
        }
    }

6.测试

6.1 编程AOP实现

写两个特性实现,继承基类特性,实现Action接口逻辑,测试两个特性随意调换位置进行组装流程

internal class AOPTest1Attribut : BaseInterceptAttribute, IInterceptorAction
    {
        public void AfterAction(object?[]? args)
        {
            Console.WriteLine($"AOP1方法执行之前,args:{args[0] + "," + args[1]}");
            // throw new Exception("异常测试(异常,但依然不能影响程序执行)");
        }
        public void BeforeAction(object?[]? args, object? result)
        {
            Console.WriteLine($"AOP1方法执行之后,result:{result}");
        }
    }
    internal class AOPTest2Attribut : BaseInterceptAttribute, IInterceptorAction
    {
        public void AfterAction(object?[]? args)
        {
            Console.WriteLine($"AOP2方法执行之前,args:{args[0] + "," + args[1]}");
        }
        public void BeforeAction(object?[]? args, object? result)
        {
            Console.WriteLine($"AOP2方法执行之后,result:{result}");
        }
    }

6.2 编写测试服务

写一个简单的测试服务,就比如两个整数相加,然后标记上我们写的AOP特性

internal interface ITestService
    {
        public int Add(int a, int b);
    }
    [AOPTest2Attribut]
    [AOPTest1Attribut]
    internal class TestService : ITestService
    {
        public int Add(int a, int b)
        {
            Console.WriteLine($"正在执行--》Add({a},{b})");
            //throw new Exception("方法执行--》测试异常");
            return a + b;
        }
    }

6.3 调用

1.把服务注册到IOC

2.调用创建代理类的工厂

3.调用测试服务函数:.Add(1, 2)

IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<ITestService, TestService>();
ServiceHelp.BuildServiceProvider(serviceCollection);
//用工厂获取代理实例
var s = ProxyFactory.Create<ITestService>();
var sum = s.Add(1, 2);

6.4 效果图

AOP1->AOP2->Add(a,b)

AOP2->AOP1->Add(a,b)

代码上传至gitee,AOP流程组装分支:https://gitee.com/luoxiangbao/dynamic-proxy.git

到此这篇关于.NET Core 利用委托实现动态流程组装的文章就介绍到这了,更多相关.NET Core动态流程组装内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯