ABP文档笔记 - 事件BUS
文档:
EventBus(事件总线)
EventBus是一个单例对象,被所有类触发事件或处理事件时共享。
IEventBusConfiguration在应用启动时加载(by AbpCoreInstaller),依据它的配置决定 是所有IWindsorContainer实例共享同一条事件总线(EventBus.Default),还是每个IWindsorContainer实例创建一个自己的单例。默认使用EventBus.Default。
因为在应用中IocManager使用单例,IIocManager.IocContainer也是单一的,所以事件总线使用的就是EventBus.Default。
注入 IEventBus
使用属性注入模式:
public class TaskAppService : ApplicationService
{
public IEventBus EventBus { get; set; }
public TaskAppService()
{
EventBus = NullEventBus.Instance;
}
}
直接使用默认实例
如果你不能注入它,可以直接使用EventBus.Default。使用方式如下所示:
EventBus.Default.Trigger(...); //trigger an event
但就如同不推荐使用IocManager.Instance一样,在任何可能的地方都不建议直接使用EventBus.Default,因为它难于单元测试。
定义事件
事件定义,继承EventData
在触发一个事件前,你首先要定义它,通过一个继承自EventData的类来表现一个事件。
假设当一个任务完成后我们想触发一个事件:
public class TaskCompletedEventData : EventData
{
public int TaskId { get; set; }
}
这个类包含处理事件类所需要的属性,EventData类定义了EventSource(事件源,哪个对象触发了事件)和EventTime(何时触发的)属性。
泛型的事件定义,使用IEventDataWithInheritableGenericArgument
public class EntityEventData<TEntity> : EventData , IEventDataWithInheritableGenericArgument
{
/// <summary>
/// Related entity with this event.
/// </summary>
public TEntity Entity { get; private set; }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="entity">Related entity with this event</param>
public EntityEventData(TEntity entity)
{
Entity = entity;
}
public virtual object[] GetConstructorArgs()
{
return new object[] { Entity };
}
}
ABP框架预定义的事件
异常处理事件
命名空间Event.Bus.Exceptions中定义了ExceptionData 和 AbpHandledExceptionData,当ABP自动处理任何异常时,会触发后者。
实体修改事件
命名空间Abp.Events.Bus.Entities中为实体修改提供了泛型的事件:EntityCreationEventData
“ing”事件(例如EntityUpdating)在保存修改(SaveChanges)前触发,所以你可以在这些事件里,通过抛出异常,促使工作单元回滚,阻止操作)。“ed”事件(例如EntityUpdated)在保存修改之后被触发,也就没有机会让工作单元回滚了。
触发事件
简单例子
public class TaskAppService : ApplicationService
{
public IEventBus EventBus { get; set; }
public TaskAppService()
{
EventBus = NullEventBus.Instance;
}
public void CompleteTask(CompleteTaskInput input)
{
//TODO: complete the task on database...
EventBus.Trigger(new TaskCompletedEventData {TaskId = 42});
}
}
Trigger方法有几个重载:
EventBus.Trigger<TaskCompletedEventData>(new TaskCompletedEventData { TaskId = 42 }); //Explicitly declare generic argument
EventBus.Trigger(this, new TaskCompletedEventData { TaskId = 42 }); //Set 'event source' as 'this'
EventBus.Trigger(typeof(TaskCompletedEventData), this, new TaskCompletedEventData { TaskId = 42 }); //Call non-generic version (first argument is the type of the event class)
实体修改时事件的触发
在插入、更新或删除实体时,它们被ABP自动触发。如果你有一个Person实体,你可以注册EntityCreatedEventData
参阅 ABP框架 - 实体 ,使用AggregateRoot类的DomainEvents集合。
-
AbpDbContext in Abp.EntityFramework
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken) { try { var changeReport = ApplyAbpConcepts(); var result = await base.SaveChangesAsync(cancellationToken); await EntityChangeEventHelper.TriggerEventsAsync(changeReport); return result; } catch (DbEntityValidationException ex) { LogDbEntityValidationException(ex); throw; } } protected virtual EntityChangeReport ApplyAbpConcepts() { var changeReport = new EntityChangeReport(); var userId = GetAuditUserId(); var entries = ChangeTracker.Entries().ToList(); foreach (var entry in entries) { switch (entry.State) { case EntityState.Added: CheckAndSetId(entry.Entity); CheckAndSetMustHaveTenantIdProperty(entry.Entity); CheckAndSetMayHaveTenantIdProperty(entry.Entity); SetCreationAuditProperties(entry.Entity, userId); changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Created)); break; case EntityState.Modified: SetModificationAuditProperties(entry, userId); if (entry.Entity is ISoftDelete && entry.Entity.As<ISoftDelete>().IsDeleted) { SetDeletionAuditProperties(entry.Entity, userId); changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Deleted)); } else { changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Updated)); } break; case EntityState.Deleted: CancelDeletionForSoftDelete(entry); SetDeletionAuditProperties(entry.Entity, userId); changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Deleted)); break; } AddDomainEvents(changeReport.DomainEvents, entry.Entity); } return changeReport; } protected virtual void AddDomainEvents(List<DomainEventEntry> domainEvents, object entityAsObj) { var generatesDomainEventsEntity = entityAsObj as IGeneratesDomainEvents; if (generatesDomainEventsEntity == null) { return; } if (generatesDomainEventsEntity.DomainEvents.IsNullOrEmpty()) { return; } domainEvents.AddRange(generatesDomainEventsEntity.DomainEvents.Select(eventData => new DomainEventEntry(entityAsObj, eventData))); generatesDomainEventsEntity.DomainEvents.Clear(); }
-
EntityChangeEventHelper in Abp.Events.Bus.Entities
public class EntityChangeEventHelper : ITransientDependency, IEntityChangeEventHelper { public IEventBus EventBus { get; set; } private readonly IUnitOfWorkManager _unitOfWorkManager; public EntityChangeEventHelper(IUnitOfWorkManager unitOfWorkManager) { _unitOfWorkManager = unitOfWorkManager; EventBus = NullEventBus.Instance; } public virtual void TriggerEvents(EntityChangeReport changeReport) { TriggerEventsInternal(changeReport); if (changeReport.IsEmpty() || _unitOfWorkManager.Current == null) { return; } _unitOfWorkManager.Current.SaveChanges(); } public Task TriggerEventsAsync(EntityChangeReport changeReport) { TriggerEventsInternal(changeReport); if (changeReport.IsEmpty() || _unitOfWorkManager.Current == null) { return Task.FromResult(0); } return _unitOfWorkManager.Current.SaveChangesAsync(); } public virtual void TriggerEntityCreatingEvent(object entity) { TriggerEventWithEntity(typeof(EntityCreatingEventData<>), entity, true); } public virtual void TriggerEntityCreatedEventOnUowCompleted(object entity) { TriggerEventWithEntity(typeof(EntityCreatedEventData<>), entity, false); } public virtual void TriggerEntityUpdatingEvent(object entity) { TriggerEventWithEntity(typeof(EntityUpdatingEventData<>), entity, true); } public virtual void TriggerEntityUpdatedEventOnUowCompleted(object entity) { TriggerEventWithEntity(typeof(EntityUpdatedEventData<>), entity, false); } public virtual void TriggerEntityDeletingEvent(object entity) { TriggerEventWithEntity(typeof(EntityDeletingEventData<>), entity, true); } public virtual void TriggerEntityDeletedEventOnUowCompleted(object entity) { TriggerEventWithEntity(typeof(EntityDeletedEventData<>), entity, false); } public virtual void TriggerEventsInternal(EntityChangeReport changeReport) { TriggerEntityChangeEvents(changeReport.ChangedEntities); TriggerDomainEvents(changeReport.DomainEvents); } protected virtual void TriggerEntityChangeEvents(List<EntityChangeEntry> changedEntities) { foreach (var changedEntity in changedEntities) { switch (changedEntity.ChangeType) { case EntityChangeType.Created: TriggerEntityCreatingEvent(changedEntity.Entity); TriggerEntityCreatedEventOnUowCompleted(changedEntity.Entity); break; case EntityChangeType.Updated: TriggerEntityUpdatingEvent(changedEntity.Entity); TriggerEntityUpdatedEventOnUowCompleted(changedEntity.Entity); break; case EntityChangeType.Deleted: TriggerEntityDeletingEvent(changedEntity.Entity); TriggerEntityDeletedEventOnUowCompleted(changedEntity.Entity); break; default: throw new AbpException("Unknown EntityChangeType: " + changedEntity.ChangeType); } } } protected virtual void TriggerDomainEvents(List<DomainEventEntry> domainEvents) { foreach (var domainEvent in domainEvents) { EventBus.Trigger(domainEvent.EventData.GetType(), domainEvent.SourceEntity, domainEvent.EventData); } } protected virtual void TriggerEventWithEntity(Type genericEventType, object entity, bool triggerInCurrentUnitOfWork) { var entityType = entity.GetType(); var eventType = genericEventType.MakeGenericType(entityType); if (triggerInCurrentUnitOfWork || _unitOfWorkManager.Current == null) { EventBus.Trigger(eventType, (IEventData)Activator.CreateInstance(eventType, new[] { entity })); return; } _unitOfWorkManager.Current.Completed += (sender, args) => EventBus.Trigger(eventType, (IEventData)Activator.CreateInstance(eventType, new[] { entity })); } }
事件的处理
处理一个事件,只要提供一个实现IEventHandler
public class ActivityWriter : IEventHandler<TaskCompletedEventData>, ITransientDependency
{
public void HandleEvent(TaskCompletedEventData eventData)
{
WriteActivity("A task is completed by id = " + eventData.TaskId);
}
}
处理程序的自动注册
上例因为实现了ITransientDependency,它会被注册到Ioc容器,而ABP也会自动把它们注册到事件总线,当一个事件发生,ABP使用Ioc容器得到处理程序的引用,并在事件处理后释放该引用。在ABP里,这是使用事件总线的推荐的方式。
internal class EventBusInstaller : IWindsorInstaller
{
//……
public void Install(IWindsorContainer container, IConfigurationStore store)
{
if (_eventBusConfiguration.UseDefaultEventBus)
{
container.Register(
Component.For<IEventBus>().UsingFactoryMethod(() => EventBus.Default).LifestyleSingleton()
);
}
else
{
container.Register(
Component.For<IEventBus>().ImplementedBy<EventBus>().LifestyleSingleton()
);
}
_eventBus = container.Resolve<IEventBus>();
container.Kernel.ComponentRegistered += Kernel_ComponentRegistered;
}
private void Kernel_ComponentRegistered(string key, IHandler handler)
{
if (!typeof(IEventHandler).IsAssignableFrom(handler.ComponentModel.Implementation))
{
return;
}
var interfaces = handler.ComponentModel.Implementation.GetInterfaces();
foreach (var @interface in interfaces)
{
if (!typeof(IEventHandler).IsAssignableFrom(@interface))
{
continue;
}
var genericArgs = @interface.GetGenericArguments();
if (genericArgs.Length == 1)
{
_eventBus.Register(genericArgs[0], new IocHandlerFactory(_iocResolver, handler.ComponentModel.Implementation));
}
}
}
}
public class IocHandlerFactory : IEventHandlerFactory
{
public Type HandlerType { get; private set; }
private readonly IIocResolver _iocResolver;
public IocHandlerFactory(IIocResolver iocResolver, Type handlerType)
{
_iocResolver = iocResolver;
HandlerType = handlerType;
}
public IEventHandler GetHandler()
{
return (IEventHandler)_iocResolver.Resolve(HandlerType);
}
public void ReleaseHandler(IEventHandler handler)
{
_iocResolver.Release(handler);
}
}
手动注册
public class EventBus : IEventBus
{
/// <inheritdoc/>
public IDisposable Register<TEventData>(Action<TEventData> action) where TEventData : IEventData
{
return Register(typeof(TEventData), new ActionEventHandler<TEventData>(action));
}
/// <inheritdoc/>
public IDisposable Register<TEventData>(IEventHandler<TEventData> handler) where TEventData : IEventData
{
return Register(typeof(TEventData), handler);
}
/// <inheritdoc/>
public IDisposable Register<TEventData, THandler>()
where TEventData : IEventData
where THandler : IEventHandler<TEventData>, new()
{
return Register(typeof(TEventData), new TransientEventHandlerFactory<THandler>());
}
/// <inheritdoc/>
public IDisposable Register(Type eventType, IEventHandler handler)
{
return Register(eventType, new SingleInstanceHandlerFactory(handler));
}
/// <inheritdoc/>
public IDisposable Register<TEventData>(IEventHandlerFactory handlerFactory) where TEventData : IEventData
{
return Register(typeof(TEventData), handlerFactory);
}
/// <inheritdoc/>
public IDisposable Register(Type eventType, IEventHandlerFactory handlerFactory)
{
GetOrCreateHandlerFactories(eventType)
.Locking(factories => factories.Add(handlerFactory));
return new FactoryUnregistrar(this, eventType, handlerFactory);
}
事件总线的Register方法有几个重载,也就提供了多种注册方式。
接受一个委托
EventBus.Register<TaskCompletedEventData>(eventData =>
{
WriteActivity("A task is completed by id = " + eventData.TaskId);
});
处理程序
internal class ActionEventHandler<TEventData> :
IEventHandler<TEventData>,
ITransientDependency
{
/// <summary>
/// Action to handle the event.
/// </summary>
public Action<TEventData> Action { get; private set; }
/// <summary>
/// Creates a new instance of <see cref="ActionEventHandler{TEventData}"/>.
/// </summary>
/// <param name="handler">Action to handle the event</param>
public ActionEventHandler(Action<TEventData> handler)
{
Action = handler;
}
/// <summary>
/// Handles the event.
/// </summary>
/// <param name="eventData"></param>
public void HandleEvent(TEventData eventData)
{
Action(eventData);
}
}
接受一个实现了IEventHantler的对象
EventBus.Register<TaskCompletedEventData>(new ActivityWriter());
注册为一个SingleInstanceHandlerFactory
internal class SingleInstanceHandlerFactory : IEventHandlerFactory
{
public IEventHandler HandlerInstance { get; private set; }
public SingleInstanceHandlerFactory(IEventHandler handler)
{
HandlerInstance = handler;
}
public IEventHandler GetHandler()
{
return HandlerInstance;
}
public void ReleaseHandler(IEventHandler handler)
{
}
}
接受两个泛型参数
EventBus.Register<TaskCompletedEventData, ActivityWriter>();
注册为一个TransientEventHandlerFactory
internal class TransientEventHandlerFactory<THandler> : IEventHandlerFactory
where THandler : IEventHandler, new()
{
public IEventHandler GetHandler()
{
return new THandler();
}
public void ReleaseHandler(IEventHandler handler)
{
if (handler is IDisposable)
{
(handler as IDisposable).Dispose();
}
}
}
直接注册一个IEventHandlerFactory
上面的几种注册方式,最终都是在间接调用下面这个方法
public IDisposable Register(Type eventType, IEventHandlerFactory handlerFactory)
{
GetOrCreateHandlerFactories(eventType)
.Locking(factories => factories.Add(handlerFactory));
return new FactoryUnregistrar(this, eventType, handlerFactory);
}
事件处理的取消注册
-
最简单的方式就是释放Register方法返回的值
//Register to an event... var registration = EventBus.Register<TaskCompletedEventData>(eventData => WriteActivity("A task is completed by id = " + eventData.TaskId) ); //Unregister from event registration.Dispose();
-
Unregister方法
//Create a handler var handler = new ActivityWriter(); //Register to the event EventBus.Register<TaskCompletedEventData>(handler); //Unregister from event EventBus.Unregister<TaskCompletedEventData>(handler);
-
EventBus提供了一个UnregisterAll
()方法,它反注册一个事件的所有处理程序 -
UnregisterAll()方法反注册所有事件的所有处理程序。