聊一聊为什么我要整合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定义的特性
/// <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 的一张性能比拼图

可见其实我们已经手握了一个高性能而且简单易用易扩展的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的广泛受众和稳定性,可堪一用。
本文但图一乐,请各位看官谨慎采纳,有意见请留言。
聊一聊为什么我要整合Microsoft.Extensions.DependencyInjection和Castle.Core的更多相关文章
- DotNetCore跨平台~一起聊聊Microsoft.Extensions.DependencyInjection
写这篇文章的心情:激动 Microsoft.Extensions.DependencyInjection在github上同样是开源的,它在dotnetcore里被广泛的使用,比起之前的autofac, ...
- 解析 Microsoft.Extensions.DependencyInjection 2.x 版本实现
项目使用了 Microsoft.Extensions.DependencyInjection 2.x 版本,遇到第2次请求时非常高的内存占用情况,于是作了调查,本文对 3.0 版本仍然适用. 先说结论 ...
- 使用诊断工具观察 Microsoft.Extensions.DependencyInjection 2.x 版本的内存占用
目录 准备工作 大量接口与实现类的生成 elasticsearch+kibana+apm asp.net core 应用 请求与快照 Kibana 上的请求记录 请求耗时的分析 请求内存的分析 第2次 ...
- Microsoft.Extensions.DependencyInjection 之三:展开测试
目录 前文回顾 IServiceCallSite CallSiteFactory ServiceProviderEngine CompiledServiceProviderEngine Dynamic ...
- Microsoft.Extensions.DependencyInjection 之三:反射可以一战(附源代码)
目录 前文回顾 IServiceCallSite CallSiteFactory ServiceProviderEngine CompiledServiceProviderEngine Dynamic ...
- Microsoft.Extensions.DependencyInjection 之二:使用诊断工具观察内存占用
目录 准备工作 大量接口与实现类的生成 elasticsearch+kibana+apm asp.net core 应用 请求与快照 Kibana 上的请求记录 请求耗时的分析 请求内存的分析 第2次 ...
- Microsoft.Extensions.DependencyInjection 之一:解析实现
[TOC] 前言 项目使用了 Microsoft.Extensions.DependencyInjection 2.x 版本,遇到第2次请求时非常高的内存占用情况,于是作了调查,本文对 3.0 版本仍 ...
- 使用 Microsoft.Extensions.DependencyInjection 进行依赖注入
没有 Autofac DryIoc Grace LightInject Lamar Stashbox Unity Ninject 的日子,才是好日子~~~~~~~~~~ Using .NET Core ...
- MvvmLight + Microsoft.Extensions.DependencyInjection + WpfApp(.NetCore3.1)
git clone MvvmLight失败,破网络, 就没有直接修改源码的方式来使用了 Nuget安装MvvmLightLibsStd10 使用GalaSoft.MvvmLight.Command命名 ...
- Microsoft.Extensions.DependencyInjection中的Transient依赖注入关系,使用不当会造成内存泄漏
Microsoft.Extensions.DependencyInjection中(下面简称DI)的Transient依赖注入关系,表示每次DI获取一个全新的注入对象.但是使用Transient依赖注 ...
随机推荐
- langchain中的chat models介绍和使用
简介 之前我们介绍了LLM模式,这种模式是就是文本输入,然后文本输出. chat models是基于LLM模式的更加高级的模式.他的输入和输出是格式化的chat messages. 一起来看看如何在l ...
- 简述几个我们对Redis 7开源社区所做的贡献
Redis 7 已经于2022年4月28号正式发布,其中包括了将近50个新的命令,增加了许多新的特性,并且在整个Redis 6到Redis 7的开发过程中,我也对Redis 的开源社区贡献了一些微薄的 ...
- python列表之索引及len()函数
我们在刚开始使用列表的时候,经常会遇到这种错误 list_1 = ['one', 'two', 'three', 'four', 'five'] print(list_1[5]) 这段代码看上去是没有 ...
- Echarts 饼图,legend样式美化
最后样式图: 实现代码: var myChart = echarts.init(document.getElementById('container')); let option = { /*{b}: ...
- 🔥🔥Java开发者的Python快速进修指南:网络编程及并发编程
今天我们将对网络编程和多线程技术进行讲解,这两者的原理大家都已经了解了,因此我们主要关注的是它们的写法区别.虽然这些区别并不是非常明显,但我们之所以将网络编程和多线程一起讲解,是因为在学习Java的s ...
- 时间复杂度为 O(nlogn) 的排序算法
归并排序 归并排序遵循分治的思想:将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后合并这些子问题的解来建立原问题的解,归并排序的步骤如下: 划分:分解待排序的 n 个元素的 ...
- 主数据管理系统(MDM)集成方案
在当今社会,数据已成为企业发展的宝贵财富.然而,大多数企业面临着数据散落在多个系统中.无法互相印证和共享的问题,导致数据使用效率低下.为解决这个问题,目前有两种典型途径:建设公司级系统或建立数据共享平 ...
- Centos8离线安装golang
一.下载golang 1.下载安装包 2.下载后解压. tar -zxvf go1.17.linux-amd64.tar.gz 二.配置环境变量 vim /etc/profile 1.在环境变量最后添 ...
- Java+Selenium爬取高德POI边界坐标
一.写在前面 关于爬取高德兴趣点边界坐标网上有几篇文章介绍实现方式,总的来说就是通过https://www.amap.com/detail/get/detail传入POI的ID值获取数据,BUT,如果 ...
- 神经网络优化篇:详解偏差,方差(Bias /Variance)
偏差,方差 注意到,几乎所有机器学习从业人员都期望深刻理解偏差和方差,这两个概念易学难精,即使自己认为已经理解了偏差和方差的基本概念,却总有一些意想不到的新东西出现.关于深度学习的误差问题,另一个趋势 ...