22. 事件总线
📝 模块更新日志
-
新特性
- 事件总线支持简单的
Order
编排规则 4.8.0 833c0d4 - 事件总线
.ReplaceStorerOrFallback
自定义事件源存储器方法,可在自定义初始失败时回退到默认值 4.7.6 #I602NU - 事件总线模块重试失败后支持回调 4.6.1 #I5UVMV
- 事件总线
LogEnabled
配置,可控制是否输出服务日志 #I5QLY5 - 事件总线
MessageCenter
静态类,解决从Fur v1.x
版本升级问题 a29fc7c - 事件总线工厂,支持运行时动态添加订阅程序和移除订阅程序 #I5NNQX
- 事件总线
[EventSubscribe]
事件Id
支持正则表达式匹配 #I5NNQX - 事件总线
[EventSubscribe]
支持局部失败重试配置 #I5NNQX - 事件总线
options.AddSubscriber(Type)
重载 42446078 - 事件总线
UseUtcTimestamp
选项配置,可选择使用DateTime.UtcNow
还是DateTime.Now
,默认是DateTime.Now
#I5JSEU - 事件总线模块事件
Id
支持枚举类型 2f328aa - 事件总线模块发布者
PublishAsync
和PublishDelayAsync
重载 2f328aa - 事件总线模块拓展方法:
Enum.ParseToString()
和String.ParseToEnum()
2f328aa
- 事件总线支持简单的
-
突破性变化
-
问题修复
-
其他调整
版本说明
以下内容仅限 Furion 2.20.0 +
版本使用。
22.1 关于事件总线
事件总线是对发布-订阅模式的一种 实现。它是一种集中式事件处理机制,允许不同的组件之间进行彼此通信而又不需要相互依赖,达到一种解耦的目的。

22.2 快速入门
22.2.1 定义事件处理程序
定义事件订阅者 ToDoEventSubscriber
:
// 实现 IEventSubscriber 接口
public class ToDoEventSubscriber : IEventSubscriber
{
private readonly ILogger<ToDoEventSubscriber> _logger;
public ToDoEventSubscriber(ILogger<ToDoEventSubscriber> logger)
{
_logger = logger;
}
[EventSubscribe("ToDo:Create")]
public async Task CreateToDo(EventHandlerExecutingContext context)
{
var todo = context.Source;
_logger.LogInformation("创建一个 ToDo:{Name}", todo.Payload);
await Task.CompletedTask;
}
// 支持多个
[EventSubscribe("ToDo:Create")]
[EventSubscribe("ToDo:Update")]
public async Task CreateOrUpdateToDo(EventHandlerExecutingContext context)
{
var todo = context.Source;
_logger.LogInformation("创建或更新一个 ToDo:{Name}", todo.Payload);
await Task.CompletedTask;
}
// 支持枚举类型,v3.4.3+ 版本支持
[EventSubscribe(YourEnum.Some)]
public async Task EnumHandler(EventHandlerExecutingContext context)
{
var eventEnum = context.Source.EventId.ParseToEnum(); // 将事件 Id 转换成枚举对象
await Task.CompletedTask;
}
// 支持正则表达式匹配,4.2.10+ 版本支持
[EventSubscribe("(^1[3456789][0-9]{9}$)|((^[0-9]{3,4}\\-[0-9]{3,8}$)|(^[0-9]{3,8}$)|(^\\([0-9]{3,4}\\)[0-9]{3,8}$)|(^0{0,1}13[0-9]{9}$))", FuzzyMatch = true)]
public async Task RegexHandler(EventHandlerExecutingContext context)
{
var eventId = context.Source.EventId;
await Task.CompletedTask;
}
// 支持多种异常重试配置,Furion 4.2.10+ 版本支持
[EventSubscribe("test:error", NumRetries = 3)]
[EventSubscribe("test:error", NumRetries = 3, RetryTimeout = 1000)] // 重试间隔时间
[EventSubscribe("test:error", NumRetries = 3, ExceptionTypes = new[] { typeof(ArgumentException) })] // 特定类型异常才重试
public async Task ExceptionHandler(EventHandlerExecutingContext context)
{
var eventId = context.Source.EventId;
await Task.CompletedTask;
}
// 支持简单 Order 编排,Furion 4.8.0+ 版本支持
[EventSubscribe("test:order", Order = 1)]
public async Task ExceptionHandler(EventHandlerExecutingContext context)
{
var eventId = context.Source.EventId;
await Task.CompletedTask;
}
}
22.2.2 发布事件消息
创建控制器 ToDoController
,依赖注入 IEventPublisher
服务:
public class ToDoController : ControllerBase
{
// 依赖注入事件发布者 IEventPublisher
private readonly IEventPublisher _eventPublisher;
public ToDoController(IEventPublisher eventPublisher)
{
_eventPublisher = eventPublisher;
}
// 发布 ToDo:Create 消息
public async Task CreateDoTo(string name)
{
await _eventPublisher.PublishAsync(new ChannelEventSource("ToDo:Create", name));
// 也可以延迟发布,比如延迟 3s
await _eventPublisher.PublishDelayAsync(new ChannelEventSource("ToDo:Create", name), 3000);
}
// v3.4.3+ 版本支持发送消息简化
public async Task CreateDoTo(string name)
{
await _eventPublisher.PublishAsync("ToDo:Create", name);
// 也可以延迟发布,比如延迟 3s
await _eventPublisher.PublishDelayAsync("ToDo:Create", 3000, name);
// 也支持枚举
await _eventPublisher.PublishAsync(YourEnum.Some);
}
}
22.2.3 注册事件服务
在 Startup.cs
注册 EventBus
服务:
// 注册 EventBus 服务
services.AddEventBus(builder =>
{
// 注 册 ToDo 事件订阅者
builder.AddSubscriber<ToDoEventSubscriber>();
// 通过类型注册,Furion 4.2.1+ 版本
builder.AddSubscriber(typeof(ToDoEventSubscriber));
// 批量注册事件订阅者
builder.AddSubscribers(ass1, ass2, ....);
});
懒人提醒
在 Furion
中可以不用通过 builder.AddSubscriber<T>()
方式一一注册,只需要实现 ISingleton
接口即可,如:
public class ToDoEventSubscriber : IEventSubscriber, ISingleton
{
}
这样就无需写 代码了,只需保留 builder.AddSubscriber<ToDoEventSubscriber>();
services.AddEventBus()
服务即可。
22.2.4 运行项目
运行项目并触发事件发布接口或方法。
info: Jaina.Samples.ToDoEventSubscriber[0]
创建一个 ToDo:Jaina
22.3 自定义事件源
Furion
使用 IEventSource
作为消息载体,任何实现该接口的类都可以充当消息载体。
如需自定义,只需实现 IEventSource
接口即可:
public class ToDoEventSource : IEventSource
{
public ToDoEventSource()
{
}
public ToDoEventSource(string eventId, string todoName)
{
EventId = eventId;
ToDoName = todoName;
}
// 自定义属性
public string ToDoName { get; set; }
/// <summary>
/// 事件 Id
/// </summary>
public string EventId { get; set; }
/// <summary>
/// 事件承载(携带)数据
/// </summary>
public object Payload { get; set; }
/// <summary>
/// 事件创建时间
/// </summary>
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
/// <summary>
/// 取消任务 Token
/// </summary>
/// <remarks>用于取消本次消息处理</remarks>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public CancellationToken CancellationToken { get; set; }
}
使用:
await _eventPublisher.PublishAsync(new ToDoEventSource ("ToDo:Create", "我的 ToDo Name"));