Browse Source

Implemented creating distributed events on aggregate roots.

pull/603/head
Halil ibrahim Kalkan 8 years ago
parent
commit
4904b9ec03
  1. 60
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/AggregateRoot.cs
  2. 17
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs
  3. 9
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeReport.cs
  4. 8
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/IGeneratesDomainEvents.cs
  5. 19
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs
  6. 27
      framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs
  7. 19
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/Person.cs
  8. 15
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/PersonNameChangedEto.cs
  9. 20
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs

60
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/AggregateRoot.cs

@ -7,28 +7,45 @@ namespace Volo.Abp.Domain.Entities
[Serializable] [Serializable]
public abstract class AggregateRoot : Entity, IAggregateRoot, IGeneratesDomainEvents public abstract class AggregateRoot : Entity, IAggregateRoot, IGeneratesDomainEvents
{ {
private readonly ICollection<object> _domainEvents = new Collection<object>(); private readonly ICollection<object> _localEvents = new Collection<object>();
private readonly ICollection<object> _distributedEvents = new Collection<object>();
protected virtual void AddDomainEvent(object eventData) protected virtual void AddLocalEvent(object eventData)
{ {
_domainEvents.Add(eventData); _localEvents.Add(eventData);
} }
public virtual IEnumerable<object> GetDomainEvents() protected virtual void AddDistributedEvent(object eventData)
{ {
return _domainEvents; _distributedEvents.Add(eventData);
} }
public virtual void ClearDomainEvents() public virtual IEnumerable<object> GetLocalEvents()
{ {
_domainEvents.Clear(); return _localEvents;
}
public IEnumerable<object> GetDistributedEvents()
{
return _distributedEvents;
}
public virtual void ClearLocalEvents()
{
_localEvents.Clear();
}
public void ClearDistributedEvents()
{
_distributedEvents.Clear();
} }
} }
[Serializable] [Serializable]
public abstract class AggregateRoot<TKey> : Entity<TKey>, IAggregateRoot<TKey>, IGeneratesDomainEvents public abstract class AggregateRoot<TKey> : Entity<TKey>, IAggregateRoot<TKey>, IGeneratesDomainEvents
{ {
private readonly ICollection<object> _domainEvents = new Collection<object>(); private readonly ICollection<object> _localEvents = new Collection<object>();
private readonly ICollection<object> _distributedEvents = new Collection<object>();
protected AggregateRoot() protected AggregateRoot()
{ {
@ -41,19 +58,34 @@ namespace Volo.Abp.Domain.Entities
} }
protected virtual void AddDomainEvent(object eventData) protected virtual void AddLocalEvent(object eventData)
{
_localEvents.Add(eventData);
}
protected virtual void AddDistributedEvent(object eventData)
{
_distributedEvents.Add(eventData);
}
public virtual IEnumerable<object> GetLocalEvents()
{
return _localEvents;
}
public IEnumerable<object> GetDistributedEvents()
{ {
_domainEvents.Add(eventData); return _distributedEvents;
} }
public virtual IEnumerable<object> GetDomainEvents() public virtual void ClearLocalEvents()
{ {
return _domainEvents; _localEvents.Clear();
} }
public virtual void ClearDomainEvents() public void ClearDistributedEvents()
{ {
_domainEvents.Clear(); _distributedEvents.Clear();
} }
} }
} }

17
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs

@ -82,7 +82,8 @@ namespace Volo.Abp.Domain.Entities.Events
protected virtual async Task TriggerEventsInternalAsync(EntityChangeReport changeReport) protected virtual async Task TriggerEventsInternalAsync(EntityChangeReport changeReport)
{ {
await TriggerEntityChangeEvents(changeReport.ChangedEntities); await TriggerEntityChangeEvents(changeReport.ChangedEntities);
await TriggerDomainEvents(changeReport.DomainEvents); await TriggerLocalEvents(changeReport.DomainEvents);
await TriggerDistributedEvents(changeReport.DistributedEvents);
} }
protected virtual async Task TriggerEntityChangeEvents(List<EntityChangeEntry> changedEntities) protected virtual async Task TriggerEntityChangeEvents(List<EntityChangeEntry> changedEntities)
@ -109,11 +110,19 @@ namespace Volo.Abp.Domain.Entities.Events
} }
} }
protected virtual async Task TriggerDomainEvents(List<DomainEventEntry> domainEvents) protected virtual async Task TriggerLocalEvents(List<DomainEventEntry> localEvents)
{ {
foreach (var domainEvent in domainEvents) foreach (var localEvent in localEvents)
{ {
await LocalEventBus.PublishAsync(domainEvent.EventData.GetType(), domainEvent.EventData); await LocalEventBus.PublishAsync(localEvent.EventData.GetType(), localEvent.EventData);
}
}
protected virtual async Task TriggerDistributedEvents(List<DomainEventEntry> distributedEvents)
{
foreach (var distributedEvent in distributedEvents)
{
await DistributedEventBus.PublishAsync(distributedEvent.EventData.GetType(), distributedEvent.EventData);
} }
} }

9
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeReport.cs

@ -8,20 +8,25 @@ namespace Volo.Abp.Domain.Entities.Events
public List<DomainEventEntry> DomainEvents { get; } public List<DomainEventEntry> DomainEvents { get; }
public List<DomainEventEntry> DistributedEvents { get; }
public EntityChangeReport() public EntityChangeReport()
{ {
ChangedEntities = new List<EntityChangeEntry>(); ChangedEntities = new List<EntityChangeEntry>();
DomainEvents = new List<DomainEventEntry>(); DomainEvents = new List<DomainEventEntry>();
DistributedEvents = new List<DomainEventEntry>();
} }
public bool IsEmpty() public bool IsEmpty()
{ {
return ChangedEntities.Count <= 0 && DomainEvents.Count <= 0; return ChangedEntities.Count <= 0 &&
DomainEvents.Count <= 0 &&
DistributedEvents.Count <= 0;
} }
public override string ToString() public override string ToString()
{ {
return $"[EntityChangeReport] ChangedEntities: {ChangedEntities.Count}, DomainEvents: {DomainEvents.Count}"; return $"[EntityChangeReport] ChangedEntities: {ChangedEntities.Count}, DomainEvents: {DomainEvents.Count}, DistributedEvents: {DistributedEvents.Count}";
} }
} }
} }

8
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/IGeneratesDomainEvents.cs

@ -6,8 +6,12 @@ namespace Volo.Abp.Domain.Entities
public interface IGeneratesDomainEvents public interface IGeneratesDomainEvents
{ {
IEnumerable<object> GetDomainEvents(); IEnumerable<object> GetLocalEvents();
void ClearDomainEvents(); IEnumerable<object> GetDistributedEvents();
void ClearLocalEvents();
void ClearDistributedEvents();
} }
} }

19
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs

@ -203,7 +203,7 @@ namespace Volo.Abp.EntityFrameworkCore
break; break;
} }
AddDomainEvents(changeReport.DomainEvents, entry.Entity); AddDomainEvents(changeReport, entry.Entity);
} }
protected virtual void ApplyAbpConceptsForAddedEntity(EntityEntry entry, EntityChangeReport changeReport) protected virtual void ApplyAbpConceptsForAddedEntity(EntityEntry entry, EntityChangeReport changeReport)
@ -237,7 +237,7 @@ namespace Volo.Abp.EntityFrameworkCore
changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Deleted)); changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Deleted));
} }
protected virtual void AddDomainEvents(List<DomainEventEntry> domainEvents, object entityAsObj) protected virtual void AddDomainEvents(EntityChangeReport changeReport, object entityAsObj)
{ {
var generatesDomainEventsEntity = entityAsObj as IGeneratesDomainEvents; var generatesDomainEventsEntity = entityAsObj as IGeneratesDomainEvents;
if (generatesDomainEventsEntity == null) if (generatesDomainEventsEntity == null)
@ -245,14 +245,19 @@ namespace Volo.Abp.EntityFrameworkCore
return; return;
} }
var entityEvents = generatesDomainEventsEntity.GetDomainEvents().ToArray(); var localEvents = generatesDomainEventsEntity.GetLocalEvents().ToArray();
if (entityEvents.IsNullOrEmpty()) if (localEvents.Any())
{ {
return; changeReport.DomainEvents.AddRange(localEvents.Select(eventData => new DomainEventEntry(entityAsObj, eventData)));
generatesDomainEventsEntity.ClearLocalEvents();
} }
domainEvents.AddRange(entityEvents.Select(eventData => new DomainEventEntry(entityAsObj, eventData))); var distributedEvents = generatesDomainEventsEntity.GetDistributedEvents().ToArray();
generatesDomainEventsEntity.ClearDomainEvents(); if (distributedEvents.Any())
{
changeReport.DistributedEvents.AddRange(distributedEvents.Select(eventData => new DomainEventEntry(entityAsObj, eventData)));
generatesDomainEventsEntity.ClearDistributedEvents();
}
} }
protected virtual void HandleConcurrencyStamp(EntityEntry entry) protected virtual void HandleConcurrencyStamp(EntityEntry entry)

27
framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs

@ -10,6 +10,7 @@ using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Events; using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus; using Volo.Abp.EventBus;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.EventBus.Local; using Volo.Abp.EventBus.Local;
using Volo.Abp.Guids; using Volo.Abp.Guids;
using Volo.Abp.MongoDB; using Volo.Abp.MongoDB;
@ -34,6 +35,8 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
public ILocalEventBus LocalEventBus { get; set; } public ILocalEventBus LocalEventBus { get; set; }
public IDistributedEventBus DistributedEventBus { get; set; }
public IEntityChangeEventHelper EntityChangeEventHelper { get; set; } public IEntityChangeEventHelper EntityChangeEventHelper { get; set; }
public IGuidGenerator GuidGenerator { get; set; } public IGuidGenerator GuidGenerator { get; set; }
@ -45,6 +48,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
DbContextProvider = dbContextProvider; DbContextProvider = dbContextProvider;
LocalEventBus = NullLocalEventBus.Instance; LocalEventBus = NullLocalEventBus.Instance;
DistributedEventBus = NullDistributedEventBus.Instance;
EntityChangeEventHelper = NullEntityChangeEventHelper.Instance; EntityChangeEventHelper = NullEntityChangeEventHelper.Instance;
} }
@ -306,18 +310,27 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
return; return;
} }
var entityEvents = generatesDomainEventsEntity.GetDomainEvents().ToArray(); var localEvents = generatesDomainEventsEntity.GetLocalEvents().ToArray();
if (entityEvents.IsNullOrEmpty()) if (localEvents.Any())
{ {
return; foreach (var localEvent in localEvents)
{
await LocalEventBus.PublishAsync(localEvent.GetType(), localEvent);
}
generatesDomainEventsEntity.ClearLocalEvents();
} }
foreach (var entityEvent in entityEvents) var distributedEvents = generatesDomainEventsEntity.GetDistributedEvents().ToArray();
if (distributedEvents.Any())
{ {
await LocalEventBus.PublishAsync(entityEvent.GetType(), entityEvent); foreach (var distributedEvent in distributedEvents)
} {
await DistributedEventBus.PublishAsync(distributedEvent.GetType(), distributedEvent);
}
generatesDomainEventsEntity.ClearDomainEvents(); generatesDomainEventsEntity.ClearDistributedEvents();
}
} }
} }

19
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/Person.cs

@ -41,7 +41,24 @@ namespace Volo.Abp.TestApp.Domain
var oldName = Name; var oldName = Name;
Name = name; Name = name;
AddDomainEvent(new PersonNameChangedEvent{Person = this, OldName = oldName});
AddLocalEvent(
new PersonNameChangedEvent
{
Person = this,
OldName = oldName
}
);
AddDistributedEvent(
new PersonNameChangedEto
{
Id = Id,
OldName = oldName,
NewName = Name,
TenantId = TenantId
}
);
} }
} }
} }

15
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/PersonNameChangedEto.cs

@ -0,0 +1,15 @@
using System;
namespace Volo.Abp.TestApp.Domain
{
public class PersonNameChangedEto
{
public virtual Guid Id { get; set; }
public virtual Guid? TenantId { get; set; }
public string OldName { get; set; }
public string NewName { get; set; }
}
}

20
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs

@ -3,7 +3,7 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Shouldly; using Shouldly;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.Abp.EventBus; using Volo.Abp.EventBus.Distributed;
using Volo.Abp.EventBus.Local; using Volo.Abp.EventBus.Local;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.TestApp.Domain; using Volo.Abp.TestApp.Domain;
@ -16,11 +16,13 @@ namespace Volo.Abp.TestApp.Testing
{ {
protected readonly IRepository<Person, Guid> PersonRepository; protected readonly IRepository<Person, Guid> PersonRepository;
protected readonly ILocalEventBus LocalEventBus; protected readonly ILocalEventBus LocalEventBus;
protected readonly IDistributedEventBus DistributedEventBus;
protected DomainEvents_Tests() protected DomainEvents_Tests()
{ {
PersonRepository = GetRequiredService<IRepository<Person, Guid>>(); PersonRepository = GetRequiredService<IRepository<Person, Guid>>();
LocalEventBus = GetRequiredService<ILocalEventBus>(); LocalEventBus = GetRequiredService<ILocalEventBus>();
DistributedEventBus = GetRequiredService<IDistributedEventBus>();
} }
[Fact] [Fact]
@ -28,13 +30,22 @@ namespace Volo.Abp.TestApp.Testing
{ {
//Arrange //Arrange
var isTriggered = false; var isLocalEventTriggered = false;
var isDistributedEventTriggered = false;
LocalEventBus.Subscribe<PersonNameChangedEvent>(data => LocalEventBus.Subscribe<PersonNameChangedEvent>(data =>
{ {
data.OldName.ShouldBe("Douglas"); data.OldName.ShouldBe("Douglas");
data.Person.Name.ShouldBe("Douglas-Changed"); data.Person.Name.ShouldBe("Douglas-Changed");
isTriggered = true; isLocalEventTriggered = true;
return Task.CompletedTask;
});
DistributedEventBus.Subscribe<PersonNameChangedEto>(data =>
{
data.OldName.ShouldBe("Douglas");
data.NewName.ShouldBe("Douglas-Changed");
isDistributedEventTriggered = true;
return Task.CompletedTask; return Task.CompletedTask;
}); });
@ -49,7 +60,8 @@ namespace Volo.Abp.TestApp.Testing
//Assert //Assert
isTriggered.ShouldBeTrue(); isLocalEventTriggered.ShouldBeTrue();
isDistributedEventTriggered.ShouldBeTrue();
} }
} }
} }
Loading…
Cancel
Save