From f81e87fed61688d2f4547ff1939b9d27ea508854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 19 Feb 2018 17:01:10 +0300 Subject: [PATCH] Added entity events for eventbus. --- src/Volo.Abp.Ddd/Volo.Abp.Ddd.csproj | 1 + src/Volo.Abp.Ddd/Volo/Abp/AbpDddModule.cs | 2 + .../Entities/Events/DomainEventEntry.cs | 18 +++ .../Entities/Events/EntityChangeEntry.cs | 18 +++ .../Events/EntityChangeEventHelper.cs | 131 ++++++++++++++++++ .../Entities/Events/EntityChangeReport.cs | 27 ++++ .../Entities/Events/EntityChangeType.cs | 11 ++ .../Entities/Events/EntityChangedEventData.cs | 23 +++ .../Events/EntityChangingEventData.cs | 23 +++ .../Entities/Events/EntityCreatedEventData.cs | 22 +++ .../Events/EntityCreatingEventData.cs | 22 +++ .../Entities/Events/EntityDeletedEventData.cs | 22 +++ .../Events/EntityDeletingEventData.cs | 22 +++ .../Domain/Entities/Events/EntityEventData.cs | 32 +++++ .../Entities/Events/EntityUpdatedEventData.cs | 22 +++ .../Events/EntityUpdatingEventData.cs | 22 +++ .../Events/IEntityChangeEventHelper.cs | 26 ++++ .../Events/NullEntityChangeEventHelper.cs | 60 ++++++++ 18 files changed, 504 insertions(+) create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/DomainEventEntry.cs create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangeEntry.cs create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangeReport.cs create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangeType.cs create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangedEventData.cs create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangingEventData.cs create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityCreatedEventData.cs create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityCreatingEventData.cs create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityDeletedEventData.cs create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityDeletingEventData.cs create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityEventData.cs create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityUpdatedEventData.cs create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityUpdatingEventData.cs create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs create mode 100644 src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs diff --git a/src/Volo.Abp.Ddd/Volo.Abp.Ddd.csproj b/src/Volo.Abp.Ddd/Volo.Abp.Ddd.csproj index b2d4736906..36b734da8d 100644 --- a/src/Volo.Abp.Ddd/Volo.Abp.Ddd.csproj +++ b/src/Volo.Abp.Ddd/Volo.Abp.Ddd.csproj @@ -16,6 +16,7 @@ + diff --git a/src/Volo.Abp.Ddd/Volo/Abp/AbpDddModule.cs b/src/Volo.Abp.Ddd/Volo/Abp/AbpDddModule.cs index f9db5aa2b7..ed316f6b16 100644 --- a/src/Volo.Abp.Ddd/Volo/Abp/AbpDddModule.cs +++ b/src/Volo.Abp.Ddd/Volo/Abp/AbpDddModule.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Application.Services; using Volo.Abp.Data; +using Volo.Abp.EventBus; using Volo.Abp.Guids; using Volo.Abp.Http; using Volo.Abp.Http.Modeling; @@ -19,6 +20,7 @@ namespace Volo.Abp [DependsOn(typeof(AbpObjectMappingModule))] [DependsOn(typeof(AbpMultiTenancyAbstractionsModule))] [DependsOn(typeof(AbpThreadingModule))] + [DependsOn(typeof(AbpEventBusModule))] [DependsOn(typeof(AbpValidationModule))] [DependsOn(typeof(AbpHttpAbstractionsModule))] public class AbpDddModule : AbpModule diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/DomainEventEntry.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/DomainEventEntry.cs new file mode 100644 index 0000000000..e0b645d1c5 --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/DomainEventEntry.cs @@ -0,0 +1,18 @@ +using System; + +namespace Volo.Abp.Domain.Entities.Events +{ + [Serializable] + public class DomainEventEntry + { + public object SourceEntity { get; } + + public object EventData { get; } + + public DomainEventEntry(object sourceEntity, object eventData) + { + SourceEntity = sourceEntity; + EventData = eventData; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangeEntry.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangeEntry.cs new file mode 100644 index 0000000000..844bf2a421 --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangeEntry.cs @@ -0,0 +1,18 @@ +using System; + +namespace Volo.Abp.Domain.Entities.Events +{ + [Serializable] + public class EntityChangeEntry + { + public object Entity { get; set; } + + public EntityChangeType ChangeType { get; set; } + + public EntityChangeEntry(object entity, EntityChangeType changeType) + { + Entity = entity; + ChangeType = changeType; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs new file mode 100644 index 0000000000..eb34ae34aa --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus; +using Volo.Abp.Uow; + +namespace Volo.Abp.Domain.Entities.Events +{ + /// + /// Used to trigger entity change events. + /// + public class EntityChangeEventHelper : IEntityChangeEventHelper, ITransientDependency + { + 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) //TODO: Trigger events really async! + { + 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 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 domainEvents) + { + foreach (var domainEvent in domainEvents) + { + EventBus.Trigger(domainEvent.EventData.GetType(), 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, Activator.CreateInstance(eventType, entity)); + return; + } + + _unitOfWorkManager.Current.Completed += (sender, args) => EventBus.Trigger(eventType, Activator.CreateInstance(eventType, entity)); + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangeReport.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangeReport.cs new file mode 100644 index 0000000000..1a89eb193e --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangeReport.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; + +namespace Volo.Abp.Domain.Entities.Events +{ + public class EntityChangeReport + { + public List ChangedEntities { get; } + + public List DomainEvents { get; } + + public EntityChangeReport() + { + ChangedEntities = new List(); + DomainEvents = new List(); + } + + public bool IsEmpty() + { + return ChangedEntities.Count <= 0 && DomainEvents.Count <= 0; + } + + public override string ToString() + { + return $"[EntityChangeReport] ChangedEntities: {ChangedEntities.Count}, DomainEvents: {DomainEvents.Count}"; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangeType.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangeType.cs new file mode 100644 index 0000000000..152745d2a7 --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangeType.cs @@ -0,0 +1,11 @@ +namespace Volo.Abp.Domain.Entities.Events +{ + public enum EntityChangeType : byte + { + Created = 0, + + Updated = 1, + + Deleted = 2 + } +} diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangedEventData.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangedEventData.cs new file mode 100644 index 0000000000..91c8eb6524 --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangedEventData.cs @@ -0,0 +1,23 @@ +using System; + +namespace Volo.Abp.Domain.Entities.Events +{ + /// + /// Used to pass data for an event when an entity () is changed (created, updated or deleted). + /// See , and classes. + /// + /// Entity type + [Serializable] + public class EntityChangedEventData : EntityEventData + { + /// + /// Constructor. + /// + /// Changed entity in this event + public EntityChangedEventData(TEntity entity) + : base(entity) + { + + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangingEventData.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangingEventData.cs new file mode 100644 index 0000000000..fb914ed46d --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityChangingEventData.cs @@ -0,0 +1,23 @@ +using System; + +namespace Volo.Abp.Domain.Entities.Events +{ + /// + /// Used to pass data for an event when an entity () is being changed (creating, updating or deleting). + /// See , and classes. + /// + /// Entity type + [Serializable] + public class EntityChangingEventData : EntityEventData + { + /// + /// Constructor. + /// + /// Changing entity in this event + public EntityChangingEventData(TEntity entity) + : base(entity) + { + + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityCreatedEventData.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityCreatedEventData.cs new file mode 100644 index 0000000000..a2cc1fdd6c --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityCreatedEventData.cs @@ -0,0 +1,22 @@ +using System; + +namespace Volo.Abp.Domain.Entities.Events +{ + /// + /// This type of event can be used to notify just after creation of an Entity. + /// + /// Entity type + [Serializable] + public class EntityCreatedEventData : EntityChangedEventData + { + /// + /// Constructor. + /// + /// The entity which is created + public EntityCreatedEventData(TEntity entity) + : base(entity) + { + + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityCreatingEventData.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityCreatingEventData.cs new file mode 100644 index 0000000000..39ad3c4480 --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityCreatingEventData.cs @@ -0,0 +1,22 @@ +using System; + +namespace Volo.Abp.Domain.Entities.Events +{ + /// + /// This type of event is used to notify just before creation of an Entity. + /// + /// Entity type + [Serializable] + public class EntityCreatingEventData : EntityChangingEventData + { + /// + /// Constructor. + /// + /// The entity which is being created + public EntityCreatingEventData(TEntity entity) + : base(entity) + { + + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityDeletedEventData.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityDeletedEventData.cs new file mode 100644 index 0000000000..e89e6a2241 --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityDeletedEventData.cs @@ -0,0 +1,22 @@ +using System; + +namespace Volo.Abp.Domain.Entities.Events +{ + /// + /// This type of event can be used to notify just after deletion of an Entity. + /// + /// Entity type + [Serializable] + public class EntityDeletedEventData : EntityChangedEventData + { + /// + /// Constructor. + /// + /// The entity which is deleted + public EntityDeletedEventData(TEntity entity) + : base(entity) + { + + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityDeletingEventData.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityDeletingEventData.cs new file mode 100644 index 0000000000..b8e336ed3e --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityDeletingEventData.cs @@ -0,0 +1,22 @@ +using System; + +namespace Volo.Abp.Domain.Entities.Events +{ + /// + /// This type of event is used to notify just before deletion of an Entity. + /// + /// Entity type + [Serializable] + public class EntityDeletingEventData : EntityChangingEventData + { + /// + /// Constructor. + /// + /// The entity which is being deleted + public EntityDeletingEventData(TEntity entity) + : base(entity) + { + + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityEventData.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityEventData.cs new file mode 100644 index 0000000000..698648ead4 --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityEventData.cs @@ -0,0 +1,32 @@ +using System; +using Volo.Abp.EventBus; + +namespace Volo.Abp.Domain.Entities.Events +{ + /// + /// Used to pass data for an event that is related to with an object. + /// + /// Entity type + [Serializable] + public class EntityEventData : IEventDataWithInheritableGenericArgument + { + /// + /// Related entity with this event. + /// + public TEntity Entity { get; } + + /// + /// Constructor. + /// + /// Related entity with this event + public EntityEventData(TEntity entity) + { + Entity = entity; + } + + public virtual object[] GetConstructorArgs() + { + return new object[] { Entity }; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityUpdatedEventData.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityUpdatedEventData.cs new file mode 100644 index 0000000000..fcff4b3305 --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityUpdatedEventData.cs @@ -0,0 +1,22 @@ +using System; + +namespace Volo.Abp.Domain.Entities.Events +{ + /// + /// This type of event can be used to notify just after update of an Entity. + /// + /// Entity type + [Serializable] + public class EntityUpdatedEventData : EntityChangedEventData + { + /// + /// Constructor. + /// + /// The entity which is updated + public EntityUpdatedEventData(TEntity entity) + : base(entity) + { + + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityUpdatingEventData.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityUpdatingEventData.cs new file mode 100644 index 0000000000..72a401fb34 --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/EntityUpdatingEventData.cs @@ -0,0 +1,22 @@ +using System; + +namespace Volo.Abp.Domain.Entities.Events +{ + /// + /// This type of event is used to notify just before update of an Entity. + /// + /// Entity type + [Serializable] + public class EntityUpdatingEventData : EntityChangingEventData + { + /// + /// Constructor. + /// + /// The entity which is being updated + public EntityUpdatingEventData(TEntity entity) + : base(entity) + { + + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs new file mode 100644 index 0000000000..315ee7ac89 --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.Domain.Entities.Events +{ + /// + /// Used to trigger entity change events. + /// + public interface IEntityChangeEventHelper + { + void TriggerEvents(EntityChangeReport changeReport); + + Task TriggerEventsAsync(EntityChangeReport changeReport); + + void TriggerEntityCreatingEvent(object entity); + + void TriggerEntityCreatedEventOnUowCompleted(object entity); + + void TriggerEntityUpdatingEvent(object entity); + + void TriggerEntityUpdatedEventOnUowCompleted(object entity); + + void TriggerEntityDeletingEvent(object entity); + + void TriggerEntityDeletedEventOnUowCompleted(object entity); + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs new file mode 100644 index 0000000000..b5006a4806 --- /dev/null +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs @@ -0,0 +1,60 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.Domain.Entities.Events +{ + /// + /// Null-object implementation of . + /// + public class NullEntityChangeEventHelper : IEntityChangeEventHelper + { + /// + /// Gets single instance of class. + /// + public static NullEntityChangeEventHelper Instance { get; } = new NullEntityChangeEventHelper(); + + private NullEntityChangeEventHelper() + { + + } + + public void TriggerEntityCreatingEvent(object entity) + { + + } + + public void TriggerEntityCreatedEventOnUowCompleted(object entity) + { + + } + + public void TriggerEntityUpdatingEvent(object entity) + { + + } + + public void TriggerEntityUpdatedEventOnUowCompleted(object entity) + { + + } + + public void TriggerEntityDeletingEvent(object entity) + { + + } + + public void TriggerEntityDeletedEventOnUowCompleted(object entity) + { + + } + + public void TriggerEvents(EntityChangeReport changeReport) + { + + } + + public Task TriggerEventsAsync(EntityChangeReport changeReport) + { + return Task.CompletedTask; + } + } +} \ No newline at end of file