【ASP.NET Core 3.1_参考中间件源码实现自定义AOP】

本文介绍了如何通过Castle.Core库创建动态代理,实现自定义AOP扩展,将学习方法前后加入吃点东西和上厕所的逻辑。利用BaseInterceptorAttribute基类和 EatInterceptorAttribute、GoToiletInterceptorAttribute属性实现拦截器,并在ProxyInterceptor中处理调用前、后及执行过程。通过在StudentService接口上添加拦截属性,最终在控制器中展示AOP扩展的效果,模拟了类似ASP.NET Core Middleware的中间件行为。

一.参考中间件源码实现自定义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中间件的理解

 转:【ASP.NET Core 3.1_参考中间件源码实现自定义AOP】 - David.Meng - 博客园

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值