• 聊一聊为什么我要整合Microsoft.Extensions.DependencyInjection和Castle.Core


    前言

    如果用到动态代理,大家可能会有几种选择,排到前列的是Autofac+Castle、AspectCore和DoraInterception,
    我将从我当时研究的经历,以及我遇到的场景,为大家展示下
    聊一聊我为什么要费时费力的整合Microsoft.Extensions.DependencyInjection和Castle.Core

    当时遇到的场景

    直接上源码

      public interface IEventHandler
      {
          Task<bool> HandleAsync(IEvent @event);
    
          bool CanHandle(IEvent @event);
      }
    
      public interface IEventHandler<T> : IEventHandler
          where T : class, IEvent
      {
          Task<bool> HandleAsync(T @event);
    
          bool IEventHandler.CanHandle(IEvent @event) => @event.GetType() == typeof(T);//语言特性:默认实现 2024-1-15 10:23:10
    
          Task<bool> IEventHandler.HandleAsync(IEvent @event) => CanHandle((T)@event) //语言特性:默认实现 2024-1-15 10:23:10
              ? HandleAsync((T)@event)
              : Task.FromResult(false);
      }
    
    public interface IEvent
    {
         public long Id { get; set; }
         public DateTime OccurredOn { get; set; }
    }
    

    如上所示的接口定义了一个事件处理接口,其中HandleAsync方法是事件处理的入口,CanHandle方法用于判断事件是否可以处理,在程序解耦、异步、削峰填谷等场景中,如上的接口可以有很多的应用,也可以扩展到内存级别、RabbitMQ、Redis、Kafka、RocketMQ等中间件的适配的事件处理器,以提供更强大的性能和更丰富的应用场景。所以说这是一个比较通用的场景。
    我们将为该处理器提供一个检查幂等的拦截器( Idempotent)

    AspectCore

    事件定义如下

     public class CatchLoggingOccurredEvent : IEvent
     {
         protected CatchLoggingOccurredEvent()
         {
             OccurredOn = DateTime.Now;
         }
    
         public CatchLoggingOccurredEvent(long id)
             : this()
         {
             Id = id;
         }
    
         public long Id { get; set; }
         public DateTime OccurredOn { get; set; }
     }
    

    事件处理器及Aspecore定义的特性

    /// 
    /// 
    /// 
    public class CatchLoggingOccurredEventHandler
    : IEventHandler<CatchLoggingOccurredEvent>
    {
        [Idempotent]
        public async virtual Task<bool> HandleAsync(CatchLoggingOccurredEvent @event)
        {
            await Console.Out.WriteLineAsync($"{nameof(CatchLoggingOccurredEventHandler)}处理事件:\t事件【{@event.Id}】@@@@@@发生于【{@event.OccurredOn}】");
            return true;
        }
    }
     [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
     internal class IdempotentAttribute
         : AbstractInterceptorAttribute
     {
         public override async Task Invoke(AspectContext context, AspectDelegate next)
         {
             var logger = context.ServiceProvider.GetRequiredService>();
             logger.LogInformation("幂等检查");
             await next(context);
         }
     }
    

    执行
    报错如下
    System.TypeLoadException:“Declaration referenced in a method implementation cannot be a final method. Type: 'AspectCore.DynamicGenerated.CatchLoggingOccurredEventHandler'. Assembly: 'AspectCore.DynamicProxy.Generator, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.”
    应该是AspectCore认为我的handle方法为一个不可覆写的方法所以抛错,该问题我已提issue至 https://github.com/dotnetcore/AspectCore-Framework/issues/319 等待解决

    DoraInterception

     /// 
     /// 
     /// 
     public class CatchLoggingOccurredEventHandler
     : IEventHandler<CatchLoggingOccurredEvent>
     {
         private readonly ILogger _logger;
    
         public CatchLoggingOccurredEventHandler(ILogger logger)
         {
             _logger = logger;
         }
    
         [Idempotent]
         public async virtual Task<bool> HandleAsync(CatchLoggingOccurredEvent message)
         {
             await Console.Out.WriteLineAsync($"{nameof(CatchLoggingOccurredEventHandler)}处理事件:\t事件【{message.Id}】@@@@@@发生于【{message.OccurredOn}】");
             return true;
         }
     }
     [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
    internal class IdempotentAttribute
        : InterceptorAttribute
    {
        /// 
        /// 
        /// 
        /// 
        /// 
        public async ValueTask InvokeAsync(InvocationContext invocationContext)
        {
            var logger = invocationContext.InvocationServices.GetRequiredService>();
            logger.LogInformation("幂等检查");
            await invocationContext.ProceedAsync();
        }
    }
    

    执行 报错如下:Dora.Interception.InterceptionException:“It fails to generate proxy class. (69,130): error CS0234: 命名空间“Microsoft.Extensions”中不存在类型或命名空间名“Logging”(是否缺少程序集引用?) (69,220): error CS0012: 类型“ILogger<>”在未引用的程序集中定义。必须添加对程序集“Microsoft.Extensions.Logging.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60”的引用。”
    dorainterception 使用 SourceGenerator,这个技术处理的复杂度比较高,根据报错是 处理器中依赖的Logging组件无法解析,这个问题比较严重,因为依赖注入这个太重要了。该问题见于 pr https://github.com/jiangjinnan/Dora/pull/13

    Autofac+Castle

    为什么不想使用Autofac,笔者的考虑是Autofac虽然功能繁多,但是其实真正实际能用到的功能少之又少,大部分的功能都可以自己扩展出来。
    借用下 https://github.com/dadhi/DryIoc 的一张性能比拼图
    image

    可见其实我们已经手握了一个高性能而且简单易用易扩展的ioc框架,合并要去另寻他处,如果因为AOP技术选型的原因,选择了autofac+Castle,那何不试下 整合 Microsoft.Extensions.DependencyInjection和Castle.Core

    综上

    截止发稿为止,已经将本系列文章的研究成果总结至 https://github.com/gainorloss/microsoft-castle.git,并以发nuget至 https://www.nuget.org/packages/CastleCore.Extensions.DependencyInjection/1.1.0,
    基准测试结果差强人意。castle代理的性能是原生的几百倍分之一,考虑到castle的广泛受众和稳定性,可堪一用。
    本文但图一乐,请各位看官谨慎采纳,有意见请留言。

  • 相关阅读:
    视频怎么转gif动图?
    Leetcode652. 寻找重复的子树
    光流法详细介绍
    Codeforces暑期训练周报(7.21~7.27)
    RabbitMQ系列【12】惰性队列
    前端页面左右布局,点击左div增加动画过渡效果
    Spring 场景下突破 pebble 模板注入限制
    maya安装时,更改注册登录方式技巧
    【c++】跟webrtc学状态改变
    神经网络注意力机制可视化,人工神经网络可视化
  • 原文地址:https://www.cnblogs.com/gainorloss/p/17965140