zoukankan      html  css  js  c++  java
  • 【ASP.NET Core 3.1_参考中间件源码实现自定义AOP】

    一、参考中间件源码实现自定义AOP
    场景:在真实执行逻辑学习这个方法包一层层(学习前吃点东西、上个厕所),模拟中间件,一层层穿过
     
    思路:对象构造完,加1个动态代理,基于Castle、组装委托,来个AOP扩展,像一个俄罗斯套娃

     
    二、AOP扩展方法--ContainerAOPExtensions.cs
    2.1、Nuget引入Castle.Core.dll
     
    2.2、实现扩展方法,目的把服务包一层代理
    /// <summary>
    /// 自定义AOP扩展
    /// </summary>
    public static class ContainerAOPExtensions
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="t">对象</param>
        /// <param name="interfaceType">接口类型</param>
        /// <returns></returns>
        public static object AOP(this object t, Type interfaceType)
        {
            ProxyGenerator generator = new ProxyGenerator();
            ProxyInterceptor interceptor = new ProxyInterceptor();
            t = generator.CreateInterfaceProxyWithTarget(interfaceType, t, interceptor);
    
            return t;
        }
    }
    三、自定义拦截属性
    3.1、基类
    public abstract class BaseInterceptorAttribute : Attribute
    {
        public abstract Action Do(IInvocation invocation, Action action);
    }
    3.2、吃点东西拦截属性
    /// <summary>
    /// 学习前吃点东西
    /// </summary>
    public class EatInterceptorAttribute : BaseInterceptorAttribute
    {
        public override Action Do(IInvocation invocation, Action action)
        {
            return () =>
            {
                Console.WriteLine($"This is Eat1 {invocation.Method.Name} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
    
                //去执行真实逻辑
                action.Invoke();
    
                Console.WriteLine($"This is Eat2 {invocation.Method.Name} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
            };
        }
    }
    3.3、上个厕所拦截属性
    /// <summary>
    /// 学习前上个厕所
    /// </summary>
    public class GoToiletInterceptorAttribute : BaseInterceptorAttribute
    {
        public override Action Do(IInvocation invocation, Action action)
        {
            return () =>
            {
                Console.WriteLine($"This is GoToilet1  {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
    
                //去执行真实逻辑
                action.Invoke();
    
                Console.WriteLine($"This is GoToilet2  {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
            };
        }
    }
    四、拦截器--ProxyInterceptor.cs
    /// <summary>
    /// 拦截器
    /// </summary>
    public class ProxyInterceptor : StandardInterceptor
    {
        /// <summary>
        /// 调用前的拦截器
        /// </summary>
        /// <param name="invocation"></param>
        protected override void PreProceed(IInvocation invocation)
        {
            Console.WriteLine($"调用前的拦截器 方法名是:{invocation.Method.Name}  {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
        }
    
        /// <summary>
        /// 拦截的方法返回时调用的拦截器
        /// </summary>
        /// <param name="invocation"></param>
        protected override void PerformProceed(IInvocation invocation)
        {
            var method = invocation.Method;
            //真实逻辑包成委托--Study()--对应学生服务里的‘我要学习了’
            Action action = () => base.PerformProceed(invocation);
    
            
            if (method.IsDefined(typeof(BaseInterceptorAttribute), true))
            {
                foreach (var attribute in method.GetCustomAttributes<BaseInterceptorAttribute>().ToArray().Reverse())
                {
                    //组装、再组装委托
                    action = attribute.Do(invocation, action);
                }
            }
            //最后一次性执行委托
            action.Invoke();
        }
    
        /// <summary>
        /// 调用后的拦截器
        /// </summary>
        /// <param name="invocation"></param>
        protected override void PostProceed(IInvocation invocation)
        {
            Console.WriteLine($"调用后的拦截器 方法名是:{invocation.Method.Name}  {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
        }
    }
    五、学生接口、学生服务
    5.1、IStudentService.cs
    在接口上面加上自定义拦截属性
    /// <summary>
    /// 学生接口
    /// </summary>
    public interface IStudentService 
    {
        /// <summary>
        /// 学习
        /// </summary>
        [EatInterceptor]
        [GoToiletInterceptor]
        public void Study();
    }

    5.2、StudentService.cs

    Study()是真实逻辑
    /// <summary>
    /// 学生服务
    /// </summary>
    public class StudentService : IStudentService
    {
        /// <summary>
        /// 学习
        /// </summary>
        public void Study()
        {
            Console.WriteLine("我要学习了!");
        }
    }
     
    六、上端调用
    public class TestCustomAOPController : Controller
    {
        //学生服务接口
        private IStudentService _iStudentService = null;
    
        public TestCustomAOPController(IStudentService iStudentService)
        {
            _iStudentService = iStudentService;
        }
    public IActionResult Index() { Console.WriteLine("******************普通方法调用*********************"); _iStudentService.Study(); Console.WriteLine("*******************AOP扩展后********************"); _iStudentService = (IStudentService)_iStudentService.AOP(typeof(IStudentService)); _iStudentService.Study(); return View(); } }
    七、项目结构
     
    八、执行效果
     
     
    总结:把真实逻辑Study()方法先不执行,先包成委托传入GoToiletGoToilet里面对委托组装后返回一个委托,再次把返回的委托再次传入EatEat里面对委托再次组装后再返回一个委托,最后一次性执行委托
     
    委托传递,组装、再组装、最后一次性执行委托,这其实就是我对ASP.NET Core Middleware中间件的理解
    Castle、组装委托,
  • 相关阅读:
    Socket与系统调用深度分析
    需求分析:未来的图书会是怎么样的?
    构建调试Linux内核网络代码的环境MenuOS系统
    jmeter--开始
    pytest---api
    pytest---mark
    pytest---数据处理
    pytest---fixture运行规则
    pytest---allure(mac版本)
    pytest---pytest.ini
  • 原文地址:https://www.cnblogs.com/menglin2010/p/13971506.html
Copyright © 2011-2022 走看看