首页 > 其他分享 >在Biwen.QuickApi中整合一个极简的发布订阅(事件总线)

在Biwen.QuickApi中整合一个极简的发布订阅(事件总线)

时间:2024-05-10 12:55:58浏览次数:24  
标签:极简 Task return CancellationToken Biwen public QuickApi logger event

闲来无聊在我的Biwen.QuickApi中实现一下极简的事件总线,其实代码还是蛮简单的,对于初学者可能有些帮助 就贴出来,有什么不足的地方也欢迎板砖交流~

首先定义一个事件约定的空接口

    public interface IEvent{}

然后定义事件订阅者接口

public interface IEventSubscriber<T> where T : IEvent
    {
        Task HandleAsync(T @event, CancellationToken ct);
        /// <summary>
        /// 执行排序
        /// </summary>
        int Order { get; }

        /// <summary>
        /// 如果发生错误是否抛出异常,将阻塞后续Handler
        /// </summary>
        bool ThrowIfError { get; }
    }
    public abstract class EventSubscriber<T> : IEventSubscriber<T> where T : IEvent
    {
        public abstract Task HandleAsync(T @event, CancellationToken ct);
        public virtual int Order => 0;
        /// <summary>
        /// 默认不抛出异常
        /// </summary>
        public virtual bool ThrowIfError => false;
    }

接着就是发布者


internal class Publisher(IServiceProvider serviceProvider)
{
	public async Task PublishAsync<T>(T @event, CancellationToken ct) where T : IEvent
	{
		var handlers = serviceProvider.GetServices<IEventSubscriber<T>>();
		if (handlers is null) return;
		foreach (var handler in handlers.OrderBy(x => x.Order))
		{
			try
			{
				await handler.HandleAsync(@event, ct);
			}
			catch
			{
				if (handler.ThrowIfError)
				{
					throw;
				}
				//todo:
			}
		}
	}
}

到此发布订阅的基本代码也就写完了.接下来就是注册发布者和所有的订阅者了

核心代码如下:

        static readonly Type InterfaceEventSubscriber = typeof(IEventSubscriber<>);
        static readonly object _lock = new();//锁
        static bool IsToGenericInterface(this Type type, Type baseInterface)
        {
            if (type == null) return false;
            if (baseInterface == null) return false;
            return type.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == baseInterface);
        }
        static IEnumerable<Type> _eventHanlers = null!;
        static IEnumerable<Type> EventHandlers
        {
            get
            {
                lock (_lock)
                    return _eventHanlers ??= ASS.InAllRequiredAssemblies.Where(x =>
                    !x.IsAbstract && x.IsPublic && x.IsClass && x.IsToGenericInterface(InterfaceEventSubscriber));
            }
        }
		    //注册EventSubscribers
            foreach (var handlerType in EventHandlers)
            {
                var baseType = handlerType.GetInterfaces().First(x => x.IsGenericType && x.GetGenericTypeDefinition() == InterfaceEventSubscriber);
                services.AddScoped(baseType, handlerType);
            }
            //注册Publisher
            services.AddScoped<Publisher>();
		

至此发布订阅的代码也就完成了!
现在我们将发布订阅封装到QuickApi中使用:


internal interface IPublisher
{
	/// <summary>
	/// Event Publish
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="event">Event</param>
	/// <returns></returns>
	Task PublishAsync<T>(T @event, CancellationToken cancellationToken) where T : IEvent;
}

然后BaseQuickApi实现IPublisher接口


internal interface IQuickApi<Req, Rsp> : IHandlerBuilder, IQuickApiMiddlewareHandler, IAntiforgeryApi, IPublisher
{
    ValueTask<Rsp> ExecuteAsync(Req request);
}

// BaseQuickApi.PublishAsync
public virtual async Task PublishAsync<T>(T @event, CancellationToken cancellationToken = default) where T : IEvent
{
    using var scope = ServiceRegistration.ServiceProvider.CreateScope();
    var publisher = scope.ServiceProvider.GetRequiredService<Publisher>();
    await publisher.PublishAsync(@event, cancellationToken);
}

至此功能完成,接下来我们测试一下:


using Biwen.QuickApi.Events;
using Microsoft.AspNetCore.Mvc;

namespace Biwen.QuickApi.DemoWeb.Apis
{
    public class MyEvent : BaseRequest<MyEvent>,IEvent
    {
        [FromQuery]
        public string? Message { get; set; }
    }

    public class MyEventHandler : EventSubscriber<MyEvent>
    {
        private readonly ILogger<MyEventHandler> _logger;
        public MyEventHandler(ILogger<MyEventHandler> logger)
        {
            _logger = logger;
        }

        public override Task HandleAsync(MyEvent @event, CancellationToken ct)
        {
            _logger.LogInformation($"msg 2 : {@event.Message}");
            return Task.CompletedTask;
        }
    }

    /// <summary>
    /// 更早执行的Handler
    /// </summary>
    public class MyEventHandler2 : EventSubscriber<MyEvent>
    {
        private readonly ILogger<MyEventHandler2> _logger;
        public MyEventHandler2(ILogger<MyEventHandler2> logger)
        {
            _logger = logger;
        }

        public override Task HandleAsync(MyEvent @event, CancellationToken ct)
        {
            _logger.LogInformation($"msg 1 : {@event.Message}");
            return Task.CompletedTask;
        }

        public override int Order => -1;

    }

    /// <summary>
    /// 抛出异常的Handler
    /// </summary>
    public class MyEventHandler3 : EventSubscriber<MyEvent>
    {
        private readonly ILogger<MyEventHandler3> _logger;
        public MyEventHandler3(ILogger<MyEventHandler3> logger)
        {
            _logger = logger;
        }

        public override Task HandleAsync(MyEvent @event, CancellationToken ct)
        {
            throw new Exception("error");
        }

        public override int Order => -2;

        public override bool ThrowIfError => false;

    }

    [QuickApi("event")]
    public class EventApi : BaseQuickApi<MyEvent>
    {
        public override async ValueTask<IResultResponse> ExecuteAsync(MyEvent request)
        {
            //publish
            await PublishAsync(request);
            return IResultResponse.Content("send event");
        }
    }
}

最后我们运行项目测试一下功能:

curl -X 'GET' \
  'http://localhost:5101/quick/event?Message=hello%20world' \
  -H 'accept: */*'

image

源代码我发布到了GitHub,欢迎star! https://github.com/vipwan/Biwen.QuickApi

标签:极简,Task,return,CancellationToken,Biwen,public,QuickApi,logger,event
From: https://www.cnblogs.com/vipwan/p/18184088

相关文章

  • 神经网络极简入门
    神经网络是深度学习的基础,正是深度学习的兴起,让停滞不前的人工智能再一次的取得飞速的发展。其实神经网络的理论由来已久,灵感来自仿生智能计算,只是以前限于硬件的计算能力,没有突出的表现,直至谷歌的AlphaGO的出现,才让大家再次看到神经网络相较于传统机器学习的优异表现。本文主要......
  • 班级擂台(光荣)榜 - 极简教育小工具
        擂台(光荣)榜是一款高效的工具,能够迅速展示学生在各个时期的总得分排名。用户可以根据左上角的日期搜索特定时间段内班级学生的排名,也可以根据右上角的“本周”、“上周”、“本月”和“上月”快速定位近期学生的综合名次。在主界面的左侧,系统会自动汇总各小组成员的得......
  • openGauss2.0.0极简版安装
    openGauss2.0.0极简版安装openGauss的安装在官方文档的描述中,一直以企业生产环境为标准进行安装部署。但在个人基本的功能测试需求下,这样的安装操作显得有些复杂。在openGauss2.0.0版本中(2021.03.31发布)新增了极简版的软件包,极简版安装的使用主体主要针对高校和个人测试......
  • 10个极简Python代码
    1、列表重复元素判定以下方法可以检查给定列表是不是存在重复元素,它会使用set()函数来移除所有重复元素。2、字符元素组成判定检查两个字符串的组成元素是不是一样的。3、内存占用4、字节占用下面的代码块可以检查字符串占用的字节数。5、打印N次字符串该......
  • 《模版模式(极简c++)》
            本文章属于专栏-概述-《设计模式(极简c++版)》-CSDN博客       本章简要说明适配器模式。本文分为模式说明、本质思想、实践建议、代码示例四个部分。模式说明方案:模版模式定义了一个逻辑的骨架,将某些步骤推迟到子类中实现。父类定义了一个模版方......
  • Macm2pro成功极简安装各种架构(arch64/x86等)虚拟机
    一、背景首先心血来潮买了mac,再心血来潮想装各种服务器,折腾了一天,发现mac的两款主流虚拟机:VMwareFusion(13)和parallelsdesktop(19)根本没啥用,只能装arm64架构的虚拟机,而且我下载了Kylin-Server-10-SP1-Release-Build04-20200711-arm64还是装不了,点了install之后又跳回来,根本进......
  • 《解释器模式(极简c++)》
            本文章属于专栏-概述-《设计模式(极简c++版)》-CSDN博客模式说明方案:对每个data建立一个单点解释器对象X,dataA和dataB之间的关系,建立一个关系解释器对象Y,这里的Y处理的是X1和X2。这样,复用了解释单文本的逻辑,和多文本间关系的逻辑。优点:灵活性:易于改变......
  • 《责任链模式(极简c++)》
            本文章属于专栏-概述-《设计模式(极简c++版)》-CSDN博客模式说明方案:责任链模式将请求的发送者和接收者解耦,构成一个链条,并由多个对象对请求进行处理,直到找到合适的处理者为止。优点:实现了请求发送者和接收者的解耦,灵活性高,易于扩展,每个处理者只需关注自......
  • 《代理模式(极简c++)》
            本文章属于专栏-概述-《设计模式(极简c++版)》-CSDN博客模式说明方案:代理模式充当了客户端和实际对象之间的中介,通过引入代理对象来控制对原始对象的访问。优点:通过代理,可以实现对目标对象的控制,提供更多的功能,例如延迟加载、访问控制、日志记录等。缺点......
  • js逆向学习- 爬虫下载「极简壁纸」图片
    声明:本文章仅供学习参考,请勿滥用爬虫下载目录声明:本文章仅供学习参考,请勿滥用爬虫下载一、确定抓取思路二、顺藤摸瓜总结前言 分享下爬取「极简壁纸」网站图片的爬虫流程,主要是分享个人处理的思路。网站地址(bs64):aHR0cHM6Ly9iei56enptaC5jbi9pbmRleA== 一、确定......