文檔:html
EventBus是一個單例對象,被全部類觸發事件或處理事件時共享。數據庫
IEventBusConfiguration在應用啓動時加載(by AbpCoreInstaller),依據它的配置決定 是全部IWindsorContainer實例共享同一條事件總線(EventBus.Default),仍是每一個IWindsorContainer實例建立一個本身的單例。默認使用EventBus.Default。
框架
由於在應用中IocManager使用單例,IIocManager.IocContainer也是單一的,因此事件總線使用的就是EventBus.Default。dom
使用屬性注入模式:async
public class TaskAppService : ApplicationService { public IEventBus EventBus { get; set; } public TaskAppService() { EventBus = NullEventBus.Instance; } }
若是你不能注入它,能夠直接使用EventBus.Default。使用方式以下所示:ide
EventBus.Default.Trigger(...); //trigger an event
但就如同不推薦使用IocManager.Instance同樣,在任何可能的地方都不建議直接使用EventBus.Default,由於它難於單元測試。源碼分析
在觸發一個事件前,你首先要定義它,經過一個繼承自EventData的類來表現一個事件。單元測試
假設當一個任務完成後咱們想觸發一個事件:測試
public class TaskCompletedEventData : EventData { public int TaskId { get; set; } }
這個類包含處理事件類所須要的屬性,EventData類定義了EventSource(事件源,哪一個對象觸發了事件)和EventTime(什麼時候觸發的)屬性。
this
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 }; } }
命名空間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); } }
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(); } } }
上面的幾種註冊方式,最終都是在間接調用下面這個方法
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);
UnregisterAll()方法反註冊全部事件的全部處理程序。