Skip to content

Commit 770eafa

Browse files
authored
Merge pull request #97 from cnblogs/use-aggregate-exception
feat: throw aggregate exceptions when publishing domain event
2 parents fbd175a + b3a755a commit 770eafa

File tree

3 files changed

+51
-13
lines changed

3 files changed

+51
-13
lines changed

src/Cnblogs.Architecture.Ddd.Domain.Abstractions/DomainEvent.cs

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
using MediatR;
2-
3-
namespace Cnblogs.Architecture.Ddd.Domain.Abstractions;
1+
namespace Cnblogs.Architecture.Ddd.Domain.Abstractions;
42

53
/// <summary>
64
/// 领域事件基类。
75
/// </summary>
8-
public abstract record DomainEvent : IDomainEvent, INotification
6+
public abstract record DomainEvent : IDomainEvent
97
{
108
/// <summary>
119
/// 领域事件生成时间。

src/Cnblogs.Architecture.Ddd.Infrastructure.Abstractions/DispatchDomainEventExtensions.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System.Runtime.ExceptionServices;
21
using Cnblogs.Architecture.Ddd.Domain.Abstractions;
32

43
// ReSharper disable once CheckNamespace
@@ -16,7 +15,7 @@ public static class DispatchDomainEventExtensions
1615
/// <param name="events">要发布的领域事件。</param>
1716
public static async Task DispatchDomainEventsAsync(this IMediator mediator, IEnumerable<IDomainEvent> events)
1817
{
19-
Exception? e = null;
18+
List<Exception>? exceptions = null;
2019
foreach (var domainEvent in events)
2120
{
2221
try
@@ -25,13 +24,14 @@ public static async Task DispatchDomainEventsAsync(this IMediator mediator, IEnu
2524
}
2625
catch (Exception exception)
2726
{
28-
e ??= exception;
27+
exceptions ??= new List<Exception>();
28+
exceptions.Add(exception);
2929
}
3030
}
3131

32-
if (e is not null)
32+
if (exceptions?.Count > 0)
3333
{
34-
ExceptionDispatchInfo.Capture(e).Throw();
34+
throw new AggregateException(exceptions);
3535
}
3636
}
3737
}

test/Cnblogs.Architecture.UnitTests/Infrastructure/EntityFramework/BaseRepositoryTests.cs

+44-4
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public async Task GetEntityAsync_ThenInclude_NotNullAsync()
9090
}
9191

9292
[Fact]
93-
public async Task SaveEntitiesAsync_CallBeforeUpdateForRelatedEntityAsync()
93+
public async Task SaveEntitiesAsync_CallBeforeUpdateForRelatedEntity_UpdateDateUpdatedAsync()
9494
{
9595
// Arrange
9696
var entity = new EntityGenerator<FakeBlog>(new FakeBlog())
@@ -118,7 +118,7 @@ public async Task SaveEntitiesAsync_CallBeforeUpdateForRelatedEntityAsync()
118118
}
119119

120120
[Fact]
121-
public async Task SaveEntitiesAsync_DispatchEntityDomainEventsAsync()
121+
public async Task SaveEntitiesAsync_DispatchEntityDomainEvents_DispatchAllAsync()
122122
{
123123
// Arrange
124124
var entity = new EntityGenerator<FakeBlog>(new FakeBlog())
@@ -156,7 +156,7 @@ public async Task SaveEntitiesAsync_DispatchEntityDomainEventsAsync()
156156
}
157157

158158
[Fact]
159-
public async Task SaveEntitiesAsync_DispatchRelatedEntityDomainEventsAsync()
159+
public async Task SaveEntitiesAsync_DispatchRelatedEntityDomainEvents_DispatchAllAsync()
160160
{
161161
// Arrange
162162
var entity = new EntityGenerator<FakeBlog>(new FakeBlog())
@@ -195,7 +195,7 @@ public async Task SaveEntitiesAsync_DispatchRelatedEntityDomainEventsAsync()
195195
}
196196

197197
[Fact]
198-
public async Task SaveEntitiesAsync_DispatchEntityDomainEventsWithGeneratedIdAsync()
198+
public async Task SaveEntitiesAsync_DispatchEntityDomainEventsWithGeneratedId_DispatchAllAsync()
199199
{
200200
// Arrange
201201
var entity = new EntityGenerator<FakeBlog>(new FakeBlog())
@@ -228,4 +228,44 @@ public async Task SaveEntitiesAsync_DispatchEntityDomainEventsWithGeneratedIdAsy
228228
It.IsAny<CancellationToken>()),
229229
Times.Exactly(entity.Posts.Count));
230230
}
231+
232+
[Fact]
233+
public async Task SaveEntitiesAsync_DispatchEntityDomainEventsWithMultipleExceptions_ThrowAggregateExceptionsAsync()
234+
{
235+
// Arrange
236+
var entity = new EntityGenerator<FakeBlog>(new FakeBlog())
237+
.Setup(x => x.DateUpdated = DateTimeOffset.Now.AddDays(-1))
238+
.HasManyForEachEntity(
239+
x => x.Posts,
240+
x => x.Blog,
241+
new EntityGenerator<FakePost>(new FakePost()).Setup(
242+
x => x.DateUpdated = DateTimeOffset.Now.AddDays(-1)))
243+
.GenerateSingle();
244+
var db = new FakeDbContext(
245+
new DbContextOptionsBuilder<FakeDbContext>().UseInMemoryDatabase("inmemory").Options);
246+
var mediator = new Mock<IMediator>();
247+
mediator.Setup(x => x.Publish(It.IsAny<IDomainEvent>(), It.IsAny<CancellationToken>()))
248+
.Throws<ArgumentException>();
249+
var repository = new TestRepository(mediator.Object, db);
250+
251+
// Act
252+
entity.AddDomainEvent(id => new FakeDomainEvent(id, 1));
253+
entity.Posts.ForEach(x => x.AddDomainEvent(id => new FakeDomainEvent(id, 2)));
254+
var act = async () => await repository.AddAsync(entity);
255+
256+
// Assert
257+
var eventCount = 1 + entity.Posts.Count;
258+
(await act.Should().ThrowAsync<AggregateException>()).And.InnerExceptions.Should()
259+
.HaveCount(eventCount);
260+
mediator.Verify(
261+
x => x.Publish(
262+
It.Is<IDomainEvent>(d => ((FakeDomainEvent)d).Id != 0 && ((FakeDomainEvent)d).FakeValue == 1),
263+
It.IsAny<CancellationToken>()),
264+
Times.Once);
265+
mediator.Verify(
266+
x => x.Publish(
267+
It.Is<IDomainEvent>(d => ((FakeDomainEvent)d).Id != 0 && ((FakeDomainEvent)d).FakeValue == 2),
268+
It.IsAny<CancellationToken>()),
269+
Times.Exactly(entity.Posts.Count));
270+
}
231271
}

0 commit comments

Comments
 (0)