实现极简的事件总线

在Biwen.QuickApi中实现了一个极简的事件总线,代码简单易懂,对初学者可能有一定帮助。以下是相关代码,欢迎交流和提出改进建议。

首先,我们定义了一个事件约定的空接口:

public interface IEvent{}

接着定义了事件订阅者接口:

public interface IEventSubscriber<T> where T : IEvent
{
    Task HandleAsync(T @event, CancellationToken ct);
    int Order { get; }
    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;
    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();//锁

//注册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
{
    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
{
    // 代码略
}

最后,我们运行项目进行测试:

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

源代码已发布到GitHub,欢迎star!
GitHub链接

未经允许不得转载:大白鲨游戏网 » 实现极简的事件总线