Event.Publish - dotnet-shashlik/shashlik.eventbus GitHub Wiki
事件类需实现接口 IEvent,IEvent 仅用于约束与规范,没有实际业务意义。事件分为普通事件和延迟事件,区别仅在于发布时是否指定延迟时间。
public class NewUserEvent : IEvent
{
public string Id { get; set; }
public string Name { get; set; }
}
public class NewUserPromotionEvent : IEvent
{
public string Id { get; set; }
public string Name { get; set; }
public string PromotionId { get; set; }
}事件名称和事件处理器名称默认规则为 {Type.Name}.{Environment},对应消息队列中的 routingKey/topic、queue/groupId。可通过 [EventBusName] 特性显式声明名称:
[EventBusName("order.created")]
public class OrderCreatedEvent : IEvent
{
// ...
}以 RabbitMQ + Production 环境为例:
-
[EventBusName("order.created")]→ 路由到order.created.Production - 无特性 → 路由到
OrderCreatedEvent.Production
事件发布通过 IEventPublisher 接口:
public interface IEventPublisher
{
Task PublishAsync<TEvent>(
TEvent @event,
ITransactionContext? transactionContext,
IDictionary<string, string>? additionalItems = null,
CancellationToken cancellationToken = default
) where TEvent : IEvent;
Task PublishAsync<TEvent>(
TEvent @event,
DateTimeOffset delayAt,
ITransactionContext? transactionContext,
IDictionary<string, string>? additionalItems = null,
CancellationToken cancellationToken = default
) where TEvent : IEvent;
}参数说明:
-
TEvent @event:事件实例 -
DateTimeOffset delayAt:延迟执行时间,小于等于当前时间时作为非延迟事件 -
ITransactionContext? transactionContext:事务上下文,不需要事务一致性时传null -
IDictionary<string, string>? additionalItems:附加数据,EventBus 默认添加以下 key,请勿重复:-
eventbus-msg-id:消息 ID -
eventbus-send-at:发送时间 -
eventbus-delay-at:延迟执行时间 -
eventbus-event-name:事件名称
-

消息数据与业务数据在同一事务中提交或回滚,EventBus 确认消息已提交后才执行真正的发送。
public interface ITransactionContext
{
bool IsDone();
}已有实现:
-
RelationDbStorageTransactionContext:关系型数据库事务(基于IDbTransaction) -
XaTransactionContext:XA 分布式事务(基于TransactionScope) -
MongoDbTransactionContext:MongoDB 事务(基于IClientSessionHandle)
引入包 Shashlik.EventBus.Extensions.EfCore,通过 DbContext 直接发布事件,自动共享事务:
using var tran = await DbContext.Database.BeginTransactionAsync();
try
{
// 业务逻辑...
// 自动使用 DbContext 当前事务上下文
await DbContext.PublishEventAsync(new NewUserEvent { Id = user.Id, Name = input.Name });
// 发布延迟事件
await DbContext.PublishEventAsync(
new NewUserPromotionEvent { Id = user.Id, Name = input.Name, PromotionId = "1" },
DateTimeOffset.Now.AddMinutes(30));
await tran.CommitAsync();
}
catch
{
await tran.RollbackAsync();
}也可以手动获取事务上下文:
var txContext = DbContext.GetTransactionContext();
await EventPublisher.PublishAsync(newEvent, txContext);Shashlik.EventBus.RelationDbStorage 内置 FreeSql 事务上下文扩展,无需额外安装包:
// 同线程事务 (fsql.Transaction(() => ...) 场景)
var txContext = fsql.GetCurrentThreadTransactionContext();
// 从 IUnitOfWork 获取
var txContext = unitOfWork.GetTransactionContextFromUnitOfWork();
// 从 IUnitOfWorkManager 获取
var txContext = unitOfWorkManager.GetTransactionContextFromUnitOfWorkManager();
await EventPublisher.PublishAsync(newEvent, txContext);引入包 Shashlik.EventBus.Extensions.SqlSugar:
// 从 IAdo 获取
var txContext = ado.GetTransactionContext();
// 从 ISqlSugarClient 获取
var txContext = sqlSugarClient.GetTransactionContext();
// 从 ISugarUnitOfWork 获取
var txContext = sugarUnitOfWork.GetTransactionContext();
await EventPublisher.PublishAsync(newEvent, txContext);using var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
try
{
// 业务逻辑...
await EventPublisher.PublishAsync(new NewUserEvent { ... }, XaTransactionContext.Current);
scope.Complete();
}
catch
{
// 回滚,消息数据也将回滚
}注意:
XaTransactionContext.Current对事务是否提交的判断延迟到TransactionScope的 Dispose 后,因此必须 DisposeTransactionScope。
如果你使用其他 ORM 或直接操作 IDbTransaction,可以手动构造:
using var conn = new MySqlConnection("...");
await conn.OpenAsync();
using var tran = await conn.BeginTransactionAsync();
try
{
// 业务逻辑...
await EventPublisher.PublishAsync(
new NewUserEvent { Id = "1", Name = "张三" },
tran.ToTransactionContext() // IDbTransaction 扩展方法
);
await tran.CommitAsync();
}
catch
{
await tran.RollbackAsync();
}