Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
<PackageId>Luxoft.Bss.Platform.Events.Abstractions</PackageId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MediatR"/>
<ProjectReference Include="..\Bss.Platform.Mediation.Abstractions\Bss.Platform.Mediation.Abstractions.csproj"/>
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion src/Bss.Platform.Events.Abstractions/IDomainEvent.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using MediatR;
using Bss.Platform.Mediation.Abstractions;

namespace Bss.Platform.Events.Abstractions;

Expand Down
2 changes: 1 addition & 1 deletion src/Bss.Platform.Events.Abstractions/IIntegrationEvent.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using MediatR;
using Bss.Platform.Mediation.Abstractions;

namespace Bss.Platform.Events.Abstractions;

Expand Down
11 changes: 6 additions & 5 deletions src/Bss.Platform.Events/Bss.Platform.Events.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
<PackageId>Luxoft.Bss.Platform.Events</PackageId>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Bss.Platform.Events.Abstractions\Bss.Platform.Events.Abstractions.csproj" />
<ProjectReference Include="..\Bss.Platform.Events.Abstractions\Bss.Platform.Events.Abstractions.csproj"/>
<ProjectReference Include="..\Bss.Platform.Mediation.Abstractions\Bss.Platform.Mediation.Abstractions.csproj"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="DotNetCore.CAP.Dashboard" />
<PackageReference Include="DotNetCore.CAP.RabbitMQ" />
<PackageReference Include="DotNetCore.CAP.SqlServer" />
<PackageReference Include="Savorboard.CAP.InMemoryMessageQueue" />
<PackageReference Include="DotNetCore.CAP.Dashboard"/>
<PackageReference Include="DotNetCore.CAP.RabbitMQ"/>
<PackageReference Include="DotNetCore.CAP.SqlServer"/>
<PackageReference Include="Savorboard.CAP.InMemoryMessageQueue"/>
</ItemGroup>
</Project>
3 changes: 1 addition & 2 deletions src/Bss.Platform.Events/Publishers/DomainEventPublisher.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Bss.Platform.Events.Abstractions;

using MediatR;
using Bss.Platform.Mediation.Abstractions;

namespace Bss.Platform.Events.Publishers;

Expand Down
3 changes: 3 additions & 0 deletions src/Bss.Platform.Mediation.Abstractions/IMediator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ Task<TResult> Send<TRequest, TResult>(TRequest request, CancellationToken cancel

Task Send<TRequest>(TRequest request, CancellationToken cancellationToken = default)
where TRequest : IRequest;

Task Publish<TNotification>(TNotification notification, CancellationToken cancellationToken = default)
where TNotification : INotification;
}
3 changes: 3 additions & 0 deletions src/Bss.Platform.Mediation.Abstractions/INotification.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Bss.Platform.Mediation.Abstractions;

public interface INotification;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Bss.Platform.Mediation.Abstractions;

public interface INotificationHandler<in TNotification> where TNotification : INotification
{
Task Handle(TNotification notification, CancellationToken cancellationToken);
}
7 changes: 4 additions & 3 deletions src/Bss.Platform.Mediation/Bss.Platform.Mediation.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Bss.Platform.Mediation.Abstractions\Bss.Platform.Mediation.Abstractions.csproj" />
<ProjectReference Include="..\Bss.Platform.Events.Abstractions\Bss.Platform.Events.Abstractions.csproj"/>
<ProjectReference Include="..\Bss.Platform.Mediation.Abstractions\Bss.Platform.Mediation.Abstractions.csproj"/>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
<PackageReference Include="Scrutor" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection"/>
<PackageReference Include="Scrutor"/>
</ItemGroup>

</Project>
11 changes: 11 additions & 0 deletions src/Bss.Platform.Mediation/Mediator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ public Task Send<TRequest>(TRequest request, CancellationToken cancellationToken
return next(request, cancellationToken);
}

public async Task Publish<TNotification>(TNotification notification, CancellationToken cancellationToken = default)
where TNotification : INotification
{
var handlers = this.ServiceProvider.GetServices<INotificationHandler<TNotification>>();

foreach (var handler in handlers)
{
await handler.Handle(notification, cancellationToken);
}
}

private TInterface[] GetBehaviors<TInterface>() =>
this.ServiceProvider
.GetServices<TInterface>()
Expand Down
63 changes: 63 additions & 0 deletions src/Tests.Unit/Platform/Mediation/NotificationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using Bss.Platform.Mediation;
using Bss.Platform.Mediation.Abstractions;

using FluentAssertions;

using Microsoft.Extensions.DependencyInjection;

using Xunit;

namespace Tests.Unit.Platform.Mediation;

public class NotificationTests
{
private readonly ServiceCollection services = [];

private readonly List<string> executionLog = [];

public NotificationTests()
{
this.services.AddSingleton(this.executionLog);
this.services.AddTransient<IMediator, Mediator>();
}

public record AlertNotification : INotification;

public class AlertHandler1(List<string> log) : INotificationHandler<AlertNotification>
{
public Task Handle(AlertNotification notification, CancellationToken cancellationToken)
{
log.Add("Handler1");
return Task.CompletedTask;
}
}

public class AlertHandler2(List<string> log) : INotificationHandler<AlertNotification>
{
public Task Handle(AlertNotification notification, CancellationToken cancellationToken)
{
log.Add("Handler2");
return Task.CompletedTask;
}
}

[Fact]
public async Task Publish_Notification_ExecutesAllHandlers()
{
// Arrange
this.services.AddTransient<INotificationHandler<AlertNotification>, AlertHandler1>();
this.services.AddTransient<INotificationHandler<AlertNotification>, AlertHandler2>();

var provider = this.services.BuildServiceProvider();
var mediator = provider.GetRequiredService<IMediator>();

// Act
await mediator.Publish(new AlertNotification());

// Assert
this.executionLog.Should().Contain("Handler1");
this.executionLog.Should().Contain("Handler2");
this.executionLog.Should().HaveCount(2);
}
}

111 changes: 111 additions & 0 deletions src/Tests.Unit/Platform/Mediation/RequestTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
using Bss.Platform.Mediation;
using Bss.Platform.Mediation.Abstractions;

using FluentAssertions;

using Microsoft.Extensions.DependencyInjection;

using Xunit;

namespace Tests.Unit.Platform.Mediation;

public class RequestTests
{
private readonly ServiceCollection services = [];

private readonly List<string> executionLog = [];

public RequestTests()
{
this.services.AddSingleton(this.executionLog);
this.services.AddTransient<IMediator, Mediator>();
}

public record PingRequest(string Name) : IRequest<string>;

public class PingHandler(List<string> log) : IRequestHandler<PingRequest, string>
{
public Task<string> Handle(PingRequest request, CancellationToken cancellationToken)
{
log.Add("Handler");
return Task.FromResult($"Hello {request.Name}");
}
}

public class LoggingBehavior<TRequest, TResult>(List<string> log) : IPipelineBehavior<TRequest, TResult>
{
public async Task<TResult> Handle(TRequest request, CancellationToken ct, Func<TRequest, CancellationToken, Task<TResult>> next)
{
log.Add("Behavior Pre");
var result = await next(request, ct);
log.Add("Behavior Post");
return result;
}
}

public record VoidRequest : IRequest;

public class VoidHandler(List<string> log) : IRequestHandler<VoidRequest>
{
public Task Handle(VoidRequest request, CancellationToken cancellationToken)
{
log.Add("VoidHandler");
return Task.CompletedTask;
}
}

public class LoggingVoidBehavior<TRequest>(List<string> log) : IPipelineBehavior<TRequest>
{
public async Task Handle(TRequest request, CancellationToken ct, Func<TRequest, CancellationToken, Task> next)
{
log.Add("VoidBehavior Pre");
await next(request, ct);
log.Add("VoidBehavior Post");
}
}

[Fact]
public async Task Send_RequestWithResult_ExecutesBehaviorsAndHandler()
{
// Arrange
this.services.AddTransient<IPipelineBehavior<PingRequest, string>, LoggingBehavior<PingRequest, string>>();
this.services.AddTransient<IRequestHandler<PingRequest, string>, PingHandler>();

var provider = this.services.BuildServiceProvider();
var mediator = provider.GetRequiredService<IMediator>();

// Act
var result = await mediator.Send<PingRequest, string>(new PingRequest("World"));

// Assert
result.Should().Be("Hello World");
this.executionLog.Should()
.ContainInOrder(
"Behavior Pre",
"Handler",
"Behavior Post"
);
}

[Fact]
public async Task Send_VoidRequest_ExecutesBehaviorsAndHandler()
{
// Arrange
this.services.AddTransient<IPipelineBehavior<VoidRequest>, LoggingVoidBehavior<VoidRequest>>();
this.services.AddTransient<IRequestHandler<VoidRequest>, VoidHandler>();

var provider = this.services.BuildServiceProvider();
var mediator = provider.GetRequiredService<IMediator>();

// Act
await mediator.Send(new VoidRequest());

// Assert
this.executionLog.Should()
.ContainInOrder(
"VoidBehavior Pre",
"VoidHandler",
"VoidBehavior Post"
);
}
}
4 changes: 4 additions & 0 deletions src/Tests.Unit/Tests.Unit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@

<ItemGroup>
<PackageReference Include="FluentAssertions"/>
<PackageReference Include="Microsoft.Extensions.DependencyInjection"/>
<PackageReference Include="Microsoft.NET.Test.Sdk"/>
<PackageReference Include="xunit"/>
<PackageReference Include="xunit.runner.visualstudio"/>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Bss.Platform.Mediation.Abstractions\Bss.Platform.Mediation.Abstractions.csproj" />
<ProjectReference Include="..\Bss.Platform.NHibernate.UnitTesting\Bss.Platform.NHibernate.UnitTesting.csproj"/>
<ProjectReference Include="..\Bss.Platform.Mediation\Bss.Platform.Mediation.csproj" />
<ProjectReference Include="..\Bss.Platform.Mediation.Abstractions\Bss.Platform.Mediation.Abstractions.csproj" />
</ItemGroup>
</Project>