首页 > 其他分享 >聊一聊为什么我要整合Microsoft.Extensions.DependencyInjection和Castle.Core

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

时间:2024-01-15 12:55:25浏览次数:47  
标签:Core Task HandleAsync event 我要 聊一聊 Extensions logger public

前言

如果用到动态代理,大家可能会有几种选择,排到前列的是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定义的特性

/// <summary>
/// 
/// </summary>
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<ILogger<IdempotentAttribute>>();
         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

 /// <summary>
 /// 
 /// </summary>
 public class CatchLoggingOccurredEventHandler
 : IEventHandler<CatchLoggingOccurredEvent>
 {
     private readonly ILogger<CatchLoggingOccurredEventHandler> _logger;

     public CatchLoggingOccurredEventHandler(ILogger<CatchLoggingOccurredEventHandler> 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
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="invocationContext"></param>
    /// <returns></returns>
    public async ValueTask InvokeAsync(InvocationContext invocationContext)
    {
        var logger = invocationContext.InvocationServices.GetRequiredService<ILogger<IdempotentAttribute>>();
        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的广泛受众和稳定性,可堪一用。
本文但图一乐,请各位看官谨慎采纳,有意见请留言。

标签:Core,Task,HandleAsync,event,我要,聊一聊,Extensions,logger,public
From: https://www.cnblogs.com/gainorloss/p/17965140

相关文章

  • NetCore 使用 Consul注册服务
    第一步:配置Consul(appsettings.json)"Consul":{"ServiceName":"bpm",//当前服务名称"IP":"127.0.0.1",//当前服务IP"Weight":"1","Port":"5002"//当前服务端口}第......
  • PAT乙级 P1003 我要通过!
    题目链接:由于需要统计字符串中各字符的出现次数,考虑使用\(\rmmap\)来进行统计。字符串中只有\(\rmP,A,T\)三种字母\(\longrightarrow\rmmap.size()==3\)题目仅给出了几条规则,因此我们将可能正确的结果罗列出来,看看能否找到一些规律。分析:任意形如xPATx的字符串都可以......
  • F1 score 与 平均精度 mAP
    F1score与平均精度mAP可以衡量分类模型的性能。首先先看精确率与召回率的概念。精确率与召回率对于某方概率极低的逻辑回归(例如某种罕见病症的确诊),单纯的准度(是否能正确判断病人是否得病)并不足够。毕竟,若算法只会给出negative的判断也能拥有高准度。真阳性(TP),假阳性(FP),真......
  • .Net Core 系列: 集成 Consul 实现 服务注册与健康检查
    目录什么是Consul?安装和运行ConsulAsp.NetCore如何集成Consul实现服务注册和健康检查Consul.AspNetCore中的AddConsul和AddConsulServiceRegistration方法究竟做了什么?AddConsul方法AddConsulServiceRegistration方法配置Consul检查服务封装成扩......
  • .Net Core 系列: 集成 CORS跨域配置
    .NetCore系列:集成CORS跨域配置  目录什么是CORS?Asp.NetCore种如何配置CORS?CorsPolicyBuilder类详解注册以及使用策略三种方式EnableCors和DisableCors特性关于带证书与不带证书代码的实现跨源(cross-origin)不带请求证书(Credentials)跨源(cross-origi......
  • 聊一聊如何整合Microsoft.Extensions.DependencyInjection和Castle.Core(完结篇)
    聊一聊如何整合Microsoft.Extensions.DependencyInjection和Castle.Core(完结篇) 合集-聊一聊如何整合Microsoft默认的Ioc容器和Castle.Core(4) 1.聊一聊如何整合Microsoft.Extensions.DependencyInjection和Castle.Core(二)01-122.聊一聊如何结合Microsoft.Extension......
  • 聊一聊如何整合Microsoft.Extensions.DependencyInjection和Castle.Core(三)
    聊一聊如何整合Microsoft.Extensions.DependencyInjection和Castle.Core(三) 合集-聊一聊如何整合Microsoft默认的Ioc容器和Castle.Core(4) 1.聊一聊如何整合Microsoft.Extensions.DependencyInjection和Castle.Core(二)01-122.聊一聊如何结合Microsoft.Extensions.De......
  • 聊一聊如何整合Microsoft.Extensions.DependencyInjection和Castle.Core(二)
    聊一聊如何整合Microsoft.Extensions.DependencyInjection和Castle.Core(二) 合集-聊一聊如何整合Microsoft默认的Ioc容器和Castle.Core(4) 1.整合Microsoft.Extensions.DependencyInjection和Castle.Core(二)01-122.聊一聊如何结合Microsoft.Extensions.DependenyI......
  • 聊一聊如何结合Microsoft.Extensions.DependenyInjection和Castle.Core
    聊一聊如何结合Microsoft.Extensions.DependenyInjection和Castle.Core 合集-聊一聊如何整合Microsoft默认的Ioc容器和Castle.Core(4) 1.聊一聊如何整合Microsoft.Extensions.DependencyInjection和Castle.Core(二)01-122.聊一聊如何结合Microsoft.Extensions.Depend......
  • 聊一聊 .NET高级调试 中必知的符号表
    一:背景1.讲故事在高级调试的旅行中,发现有不少人对符号表不是很清楚,其实简而言之符号表中记录着一些程序的生物特征,比如哪个地址是函数(签名信息),哪个地址是全局变量,静态变量,行号是多少,数据类型是什么等等,目的就是辅助我们可视化的调试,如果没有这些辅助我们看到的都是一些无意义的......