结合 AOP 轻松处理事件发布处理日志
結合 AOP 輕松處理事件發布處理日志
Intro
前段時間,實現了 EventBus 以及 EventQueue 基于 Event 的事件處理,但是沒有做日志(EventLog)相關的部分,原本想增加兩個接口, 處理事件發布日志和事件處理日志,最近用了 AOP 的思想處理了 EntityFramework 的數據變更自動審計,于是想著事件日志也用 AOP 的思想來實現,而且可能用 AOP 來處理可能會更好一些,最近自己造了一個 AOP 的輪子 —— FluentAspects,下面的示例就以它來演示了,你也可以換成自己喜歡的 AOP 組件,思想是類似的
事件日志示例
事件發布日志
事件發布日志只需要攔截事件發布的方法調用即可,在發布事件時進行攔截,在攔截器中根據需要進行日志記錄即可
事件發布者接口定義:
public?interface?IEventPublisher {///?<summary>///?publish?an?event///?</summary>///?<typeparam?name="TEvent">event?type</typeparam>///?<param?name="event">event?data</param>///?<returns>whether?the?operation?succeed</returns>bool?Publish<TEvent>(TEvent?@event)?where?TEvent?:?class,?IEventBase;///?<summary>///?publish?an?event?async///?</summary>///?<typeparam?name="TEvent">event?type</typeparam>///?<param?name="event">event?data</param>///?<returns>whether?the?operation?succeed</returns>Task<bool>?PublishAsync<TEvent>(TEvent?@event)?where?TEvent?:?class,?IEventBase; }事件發布日志攔截器:
public?class?EventPublishLogInterceptor?:?AbstractInterceptor {public?override?async?Task?Invoke(IInvocation?invocation,?Func<Task>?next){Console.WriteLine("-------------------------------");Console.WriteLine($"Event?publish?begin,?eventData:{invocation.Arguments.ToJson()}");var?watch?=?Stopwatch.StartNew();try{await?next();}catch?(Exception?ex){Console.WriteLine($"Event?publish?exception({ex})");}finally{watch.Stop();Console.WriteLine($"Event?publish?complete,?elasped:{watch.ElapsedMilliseconds}?ms");}Console.WriteLine("-------------------------------");} }事件處理日志
事件處理器接口定義:
public?interface?IEventHandler {Task?Handle(object?eventData); }事件處理日志攔截器定義:
public?class?EventHandleLogInterceptor?:?IInterceptor {public?async?Task?Invoke(IInvocation?invocation,?Func<Task>?next){Console.WriteLine("-------------------------------");Console.WriteLine($"Event?handle?begin,?eventData:{invocation.Arguments.ToJson()}");var?watch?=?Stopwatch.StartNew();try{await?next();}catch?(Exception?ex){Console.WriteLine($"Event?handle?exception({ex})");}finally{watch.Stop();Console.WriteLine($"Event?handle?complete,?elasped:{watch.ElapsedMilliseconds}?ms");}Console.WriteLine("-------------------------------");} }AOP 配置
Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(builder?=>{builder.UseStartup<Startup>();}).UseFluentAspectServiceProviderFactory(options?=>{//?攔截器配置//?攔截?`IEventPublisher`?日志,注冊事件發布日志攔截器options.InterceptType<IEventPublisher>().With<EventPublishLogInterceptor>();//?攔截?`IEventHandler`,注冊事件處理日志攔截器options.InterceptType<IEventHandler>().With<EventHandleLogInterceptor>();},?builder?=>{//?默認使用默認實現來生成代理,現在提供了?Castle?和?AspectCore?的擴展,也可以自己擴展實現自定義代理生成方式//?取消注釋使用?Castle?來生成代理//builder.UseCastleProxy();},?t?=>?t.Namespace?.StartsWith("WeihanLi")?==?false?//?要忽略的類型斷言).Build().Run();More
事件發布示例,定義了一個發布事件的中間件:
//?pageView?middleware app.Use((context,?next)?=> {var?eventPublisher?=?context.RequestServices.GetRequiredService<IEventPublisher>();eventPublisher.Publish(new?PageViewEvent(){Path?=?context.Request.Path.Value,});return?next(); });事件處理示例是用一個消息隊列的模式來處理的,示例和前面的事件的文章類似,EventConsumer 是一個后臺任務,完整代碼示例如下:
public?class?EventConsumer?:?BackgroundService {private?readonly?IEventQueue?_eventQueue;private?readonly?IEventHandlerFactory?_eventHandlerFactory;public?EventConsumer(IEventQueue?eventQueue,?IEventHandlerFactory?eventHandlerFactory){_eventQueue?=?eventQueue;_eventHandlerFactory?=?eventHandlerFactory;}protected?override?async?Task?ExecuteAsync(CancellationToken?stoppingToken){while?(!stoppingToken.IsCancellationRequested){var?queues?=?await?_eventQueue.GetQueuesAsync();if?(queues.Count?>?0){await?queues.Select(async?q?=>{var?@event?=?await?_eventQueue.DequeueAsync(q);if?(null?!=?@event){var?handlers?=?_eventHandlerFactory.GetHandlers(@event.GetType());if?(handlers.Count?>?0){await?handlers.Select(h?=>?h.Handle(@event)).WhenAll();}}}).WhenAll();}await?Task.Delay(1000,?stoppingToken);}} }完整的示例代碼可以從https://github.com/WeihanLi/WeihanLi.Common/blob/dev/samples/AspNetCoreSample 獲取
OverMore
之前在微軟的 EShopOnContainers 項目里又看到類似下面這樣的代碼,在發布事件的時候包裝一層 try ... catch 來記錄事件發布日志,相比之下,本文示例中的這種方式更為簡潔,代碼更清爽
Reference
https://www.cnblogs.com/weihanli/p/12941919.html
https://www.cnblogs.com/weihanli/p/implement-event-queue.html
https://github.com/WeihanLi/WeihanLi.Common
https://github.com/WeihanLi/WeihanLi.Common/blob/dev/samples/AspNetCoreSample/Startup.cs
總結
以上是生活随笔為你收集整理的结合 AOP 轻松处理事件发布处理日志的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用dotnet Cli向nuget发布
- 下一篇: Sql Server之旅——第十二站 对