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