聊一聊为什么我要整合Microsoft.Extensions.DependencyInjection和Castle.Core
前言
如果用到動態(tài)代理,大家可能會有幾種選擇,排到前列的是Autofac+Castle、AspectCore和DoraInterception,
我將從我當(dāng)時研究的經(jīng)歷,以及我遇到的場景,為大家展示下
聊一聊我為什么要費時費力的整合Microsoft.Extensions.DependencyInjection和Castle.Core
當(dāng)時遇到的場景
直接上源碼
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);//語言特性:默認(rèn)實現(xiàn) 2024-1-15 10:23:10
Task<bool> IEventHandler.HandleAsync(IEvent @event) => CanHandle((T)@event) //語言特性:默認(rèn)實現(xiàn) 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方法用于判斷事件是否可以處理,在程序解耦、異步、削峰填谷等場景中,如上的接口可以有很多的應(yīng)用,也可以擴(kuò)展到內(nèi)存級別、RabbitMQ、Redis、Kafka、RocketMQ等中間件的適配的事件處理器,以提供更強(qiáng)大的性能和更豐富的應(yīng)用場景。所以說這是一個比較通用的場景。
我們將為該處理器提供一個檢查冪等的攔截器( 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}】@@@@@@發(fā)生于【{@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);
}
}
執(zhí)行
報錯如下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'.”
應(yīng)該是AspectCore認(rèn)為我的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}】@@@@@@發(fā)生于【{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();
}
}
執(zhí)行 報錯如下: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,這個技術(shù)處理的復(fù)雜度比較高,根據(jù)報錯是 處理器中依賴的Logging組件無法解析,這個問題比較嚴(yán)重,因為依賴注入這個太重要了。該問題見于 pr https://github.com/jiangjinnan/Dora/pull/13
Autofac+Castle
為什么不想使用Autofac,筆者的考慮是Autofac雖然功能繁多,但是其實真正實際能用到的功能少之又少,大部分的功能都可以自己擴(kuò)展出來。
借用下 https://github.com/dadhi/DryIoc 的一張性能比拼圖
可見其實我們已經(jīng)手握了一個高性能而且簡單易用易擴(kuò)展的ioc框架,合并要去另尋他處,如果因為AOP技術(shù)選型的原因,選擇了autofac+Castle,那何不試下 整合 Microsoft.Extensions.DependencyInjection和Castle.Core
綜上
截止發(fā)稿為止,已經(jīng)將本系列文章的研究成果總結(jié)至 https://github.com/gainorloss/microsoft-castle.git,并以發(fā)nuget至 https://www.nuget.org/packages/CastleCore.Extensions.DependencyInjection/1.1.0,
基準(zhǔn)測試結(jié)果差強(qiáng)人意。castle代理的性能是原生的幾百倍分之一,考慮到castle的廣泛受眾和穩(wěn)定性,可堪一用。
本文但圖一樂,請各位看官謹(jǐn)慎采納,有意見請留言。
總結(jié)
以上是生活随笔為你收集整理的聊一聊为什么我要整合Microsoft.Extensions.DependencyInjection和Castle.Core的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 独立开发者碎碎念 1115
- 下一篇: 【scikit-learn基础】--『监