翼度科技»论坛 编程开发 .net 查看内容

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

3

主题

3

帖子

9

积分

新手上路

Rank: 1

积分
9
前言

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

直接上源码
  1.   public interface IEventHandler
  2.   {
  3.       Task<bool> HandleAsync(IEvent @event);
  4.       bool CanHandle(IEvent @event);
  5.   }
  6.   public interface IEventHandler<T> : IEventHandler
  7.       where T : class, IEvent
  8.   {
  9.       Task<bool> HandleAsync(T @event);
  10.       bool IEventHandler.CanHandle(IEvent @event) => @event.GetType() == typeof(T);//语言特性:默认实现 2024-1-15 10:23:10
  11.       Task<bool> IEventHandler.HandleAsync(IEvent @event) => CanHandle((T)@event) //语言特性:默认实现 2024-1-15 10:23:10
  12.           ? HandleAsync((T)@event)
  13.           : Task.FromResult(false);
  14.   }
  15. public interface IEvent
  16. {
  17.      public long Id { get; set; }
  18.      public DateTime OccurredOn { get; set; }
  19. }
复制代码
如上所示的接口定义了一个事件处理接口,其中HandleAsync方法是事件处理的入口,CanHandle方法用于判断事件是否可以处理,在程序解耦、异步、削峰填谷等场景中,如上的接口可以有很多的应用,也可以扩展到内存级别、RabbitMQ、Redis、Kafka、RocketMQ等中间件的适配的事件处理器,以提供更强大的性能和更丰富的应用场景。所以说这是一个比较通用的场景。
我们将为该处理器提供一个检查幂等的拦截器( Idempotent)
AspectCore

事件定义如下
  1. public class CatchLoggingOccurredEvent : IEvent
  2. {
  3.      protected CatchLoggingOccurredEvent()
  4.      {
  5.          OccurredOn = DateTime.Now;
  6.      }
  7.      public CatchLoggingOccurredEvent(long id)
  8.          : this()
  9.      {
  10.          Id = id;
  11.      }
  12.      public long Id { get; set; }
  13.      public DateTime OccurredOn { get; set; }
  14. }
复制代码
事件处理器及Aspecore定义的特性
  1. /// <summary>
  2. ///
  3. /// </summary>
  4. public class CatchLoggingOccurredEventHandler
  5. : IEventHandler<CatchLoggingOccurredEvent>
  6. {
  7.     [Idempotent]
  8.     public async virtual Task<bool> HandleAsync(CatchLoggingOccurredEvent @event)
  9.     {
  10.         await Console.Out.WriteLineAsync($"{nameof(CatchLoggingOccurredEventHandler)}处理事件:\t事件【{@event.Id}】@@@@@@发生于【{@event.OccurredOn}】");
  11.         return true;
  12.     }
  13. }
  14. [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
  15. internal class IdempotentAttribute
  16.      : AbstractInterceptorAttribute
  17. {
  18.      public override async Task Invoke(AspectContext context, AspectDelegate next)
  19.      {
  20.          var logger = context.ServiceProvider.GetRequiredService<ILogger<IdempotentAttribute>>();
  21.          logger.LogInformation("幂等检查");
  22.          await next(context);
  23.      }
  24. }
复制代码
执行
报错如下
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
  1. /// <summary>
  2. ///
  3. /// </summary>
  4. public class CatchLoggingOccurredEventHandler
  5. : IEventHandler<CatchLoggingOccurredEvent>
  6. {
  7.      private readonly ILogger<CatchLoggingOccurredEventHandler> _logger;
  8.      public CatchLoggingOccurredEventHandler(ILogger<CatchLoggingOccurredEventHandler> logger)
  9.      {
  10.          _logger = logger;
  11.      }
  12.      [Idempotent]
  13.      public async virtual Task<bool> HandleAsync(CatchLoggingOccurredEvent message)
  14.      {
  15.          await Console.Out.WriteLineAsync($"{nameof(CatchLoggingOccurredEventHandler)}处理事件:\t事件【{message.Id}】@@@@@@发生于【{message.OccurredOn}】");
  16.          return true;
  17.      }
  18. }
  19. [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
  20. internal class IdempotentAttribute
  21.     : InterceptorAttribute
  22. {
  23.     /// <summary>
  24.     ///
  25.     /// </summary>
  26.     /// <param name="invocationContext"></param>
  27.     /// <returns></returns>
  28.     public async ValueTask InvokeAsync(InvocationContext invocationContext)
  29.     {
  30.         var logger = invocationContext.InvocationServices.GetRequiredService<ILogger<IdempotentAttribute>>();
  31.         logger.LogInformation("幂等检查");
  32.         await invocationContext.ProceedAsync();
  33.     }
  34. }
复制代码
执行 报错如下: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  的一张性能比拼图

可见其实我们已经手握了一个高性能而且简单易用易扩展的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的广泛受众和稳定性,可堪一用。
本文但图一乐,请各位看官谨慎采纳,有意见请留言。

来源:https://www.cnblogs.com/gainorloss/Undeclared/17965140
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具