diff --git a/src/Bss.Platform.Events.Abstractions/Bss.Platform.Events.Abstractions.csproj b/src/Bss.Platform.Events.Abstractions/Bss.Platform.Events.Abstractions.csproj
index b0a2923..f4a5d20 100644
--- a/src/Bss.Platform.Events.Abstractions/Bss.Platform.Events.Abstractions.csproj
+++ b/src/Bss.Platform.Events.Abstractions/Bss.Platform.Events.Abstractions.csproj
@@ -3,6 +3,6 @@
Luxoft.Bss.Platform.Events.Abstractions
-
+
diff --git a/src/Bss.Platform.Events.Abstractions/IDomainEvent.cs b/src/Bss.Platform.Events.Abstractions/IDomainEvent.cs
index 82e2c5d..2f68705 100644
--- a/src/Bss.Platform.Events.Abstractions/IDomainEvent.cs
+++ b/src/Bss.Platform.Events.Abstractions/IDomainEvent.cs
@@ -1,4 +1,4 @@
-using MediatR;
+using Bss.Platform.Mediation.Abstractions;
namespace Bss.Platform.Events.Abstractions;
diff --git a/src/Bss.Platform.Events.Abstractions/IIntegrationEvent.cs b/src/Bss.Platform.Events.Abstractions/IIntegrationEvent.cs
index 256cbdc..12cc497 100644
--- a/src/Bss.Platform.Events.Abstractions/IIntegrationEvent.cs
+++ b/src/Bss.Platform.Events.Abstractions/IIntegrationEvent.cs
@@ -1,4 +1,4 @@
-using MediatR;
+using Bss.Platform.Mediation.Abstractions;
namespace Bss.Platform.Events.Abstractions;
diff --git a/src/Bss.Platform.Events/Bss.Platform.Events.csproj b/src/Bss.Platform.Events/Bss.Platform.Events.csproj
index 0ad9700..7a22725 100644
--- a/src/Bss.Platform.Events/Bss.Platform.Events.csproj
+++ b/src/Bss.Platform.Events/Bss.Platform.Events.csproj
@@ -3,12 +3,13 @@
Luxoft.Bss.Platform.Events
-
+
+
-
-
-
-
+
+
+
+
diff --git a/src/Bss.Platform.Events/Publishers/DomainEventPublisher.cs b/src/Bss.Platform.Events/Publishers/DomainEventPublisher.cs
index a3b9072..511359b 100644
--- a/src/Bss.Platform.Events/Publishers/DomainEventPublisher.cs
+++ b/src/Bss.Platform.Events/Publishers/DomainEventPublisher.cs
@@ -1,6 +1,5 @@
using Bss.Platform.Events.Abstractions;
-
-using MediatR;
+using Bss.Platform.Mediation.Abstractions;
namespace Bss.Platform.Events.Publishers;
diff --git a/src/Bss.Platform.Mediation.Abstractions/IMediator.cs b/src/Bss.Platform.Mediation.Abstractions/IMediator.cs
index e7029b1..f5b58f2 100644
--- a/src/Bss.Platform.Mediation.Abstractions/IMediator.cs
+++ b/src/Bss.Platform.Mediation.Abstractions/IMediator.cs
@@ -7,4 +7,7 @@ Task Send(TRequest request, CancellationToken cancel
Task Send(TRequest request, CancellationToken cancellationToken = default)
where TRequest : IRequest;
+
+ Task Publish(TNotification notification, CancellationToken cancellationToken = default)
+ where TNotification : INotification;
}
diff --git a/src/Bss.Platform.Mediation.Abstractions/INotification.cs b/src/Bss.Platform.Mediation.Abstractions/INotification.cs
new file mode 100644
index 0000000..fbec3b2
--- /dev/null
+++ b/src/Bss.Platform.Mediation.Abstractions/INotification.cs
@@ -0,0 +1,3 @@
+namespace Bss.Platform.Mediation.Abstractions;
+
+public interface INotification;
diff --git a/src/Bss.Platform.Mediation.Abstractions/INotificationHandler.cs b/src/Bss.Platform.Mediation.Abstractions/INotificationHandler.cs
new file mode 100644
index 0000000..295f21c
--- /dev/null
+++ b/src/Bss.Platform.Mediation.Abstractions/INotificationHandler.cs
@@ -0,0 +1,6 @@
+namespace Bss.Platform.Mediation.Abstractions;
+
+public interface INotificationHandler where TNotification : INotification
+{
+ Task Handle(TNotification notification, CancellationToken cancellationToken);
+}
diff --git a/src/Bss.Platform.Mediation/Bss.Platform.Mediation.csproj b/src/Bss.Platform.Mediation/Bss.Platform.Mediation.csproj
index 53c0bbe..c131612 100644
--- a/src/Bss.Platform.Mediation/Bss.Platform.Mediation.csproj
+++ b/src/Bss.Platform.Mediation/Bss.Platform.Mediation.csproj
@@ -7,12 +7,13 @@
-
+
+
-
-
+
+
diff --git a/src/Bss.Platform.Mediation/Mediator.cs b/src/Bss.Platform.Mediation/Mediator.cs
index 3af73e7..f10d2c7 100644
--- a/src/Bss.Platform.Mediation/Mediator.cs
+++ b/src/Bss.Platform.Mediation/Mediator.cs
@@ -39,6 +39,17 @@ public Task Send(TRequest request, CancellationToken cancellationToken
return next(request, cancellationToken);
}
+ public async Task Publish(TNotification notification, CancellationToken cancellationToken = default)
+ where TNotification : INotification
+ {
+ var handlers = this.ServiceProvider.GetServices>();
+
+ foreach (var handler in handlers)
+ {
+ await handler.Handle(notification, cancellationToken);
+ }
+ }
+
private TInterface[] GetBehaviors() =>
this.ServiceProvider
.GetServices()
diff --git a/src/Tests.Unit/Platform/Mediation/NotificationTests.cs b/src/Tests.Unit/Platform/Mediation/NotificationTests.cs
new file mode 100644
index 0000000..f054e79
--- /dev/null
+++ b/src/Tests.Unit/Platform/Mediation/NotificationTests.cs
@@ -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 executionLog = [];
+
+ public NotificationTests()
+ {
+ this.services.AddSingleton(this.executionLog);
+ this.services.AddTransient();
+ }
+
+ public record AlertNotification : INotification;
+
+ public class AlertHandler1(List log) : INotificationHandler
+ {
+ public Task Handle(AlertNotification notification, CancellationToken cancellationToken)
+ {
+ log.Add("Handler1");
+ return Task.CompletedTask;
+ }
+ }
+
+ public class AlertHandler2(List log) : INotificationHandler
+ {
+ public Task Handle(AlertNotification notification, CancellationToken cancellationToken)
+ {
+ log.Add("Handler2");
+ return Task.CompletedTask;
+ }
+ }
+
+ [Fact]
+ public async Task Publish_Notification_ExecutesAllHandlers()
+ {
+ // Arrange
+ this.services.AddTransient, AlertHandler1>();
+ this.services.AddTransient, AlertHandler2>();
+
+ var provider = this.services.BuildServiceProvider();
+ var mediator = provider.GetRequiredService();
+
+ // Act
+ await mediator.Publish(new AlertNotification());
+
+ // Assert
+ this.executionLog.Should().Contain("Handler1");
+ this.executionLog.Should().Contain("Handler2");
+ this.executionLog.Should().HaveCount(2);
+ }
+}
+
diff --git a/src/Tests.Unit/Platform/Mediation/RequestTests.cs b/src/Tests.Unit/Platform/Mediation/RequestTests.cs
new file mode 100644
index 0000000..5597df0
--- /dev/null
+++ b/src/Tests.Unit/Platform/Mediation/RequestTests.cs
@@ -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 executionLog = [];
+
+ public RequestTests()
+ {
+ this.services.AddSingleton(this.executionLog);
+ this.services.AddTransient();
+ }
+
+ public record PingRequest(string Name) : IRequest;
+
+ public class PingHandler(List log) : IRequestHandler
+ {
+ public Task Handle(PingRequest request, CancellationToken cancellationToken)
+ {
+ log.Add("Handler");
+ return Task.FromResult($"Hello {request.Name}");
+ }
+ }
+
+ public class LoggingBehavior(List log) : IPipelineBehavior
+ {
+ public async Task Handle(TRequest request, CancellationToken ct, Func> 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 log) : IRequestHandler
+ {
+ public Task Handle(VoidRequest request, CancellationToken cancellationToken)
+ {
+ log.Add("VoidHandler");
+ return Task.CompletedTask;
+ }
+ }
+
+ public class LoggingVoidBehavior(List log) : IPipelineBehavior
+ {
+ public async Task Handle(TRequest request, CancellationToken ct, Func next)
+ {
+ log.Add("VoidBehavior Pre");
+ await next(request, ct);
+ log.Add("VoidBehavior Post");
+ }
+ }
+
+ [Fact]
+ public async Task Send_RequestWithResult_ExecutesBehaviorsAndHandler()
+ {
+ // Arrange
+ this.services.AddTransient, LoggingBehavior>();
+ this.services.AddTransient, PingHandler>();
+
+ var provider = this.services.BuildServiceProvider();
+ var mediator = provider.GetRequiredService();
+
+ // Act
+ var result = await mediator.Send(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, LoggingVoidBehavior>();
+ this.services.AddTransient, VoidHandler>();
+
+ var provider = this.services.BuildServiceProvider();
+ var mediator = provider.GetRequiredService();
+
+ // Act
+ await mediator.Send(new VoidRequest());
+
+ // Assert
+ this.executionLog.Should()
+ .ContainInOrder(
+ "VoidBehavior Pre",
+ "VoidHandler",
+ "VoidBehavior Post"
+ );
+ }
+}
diff --git a/src/Tests.Unit/Tests.Unit.csproj b/src/Tests.Unit/Tests.Unit.csproj
index 77cfd7e..f82a352 100644
--- a/src/Tests.Unit/Tests.Unit.csproj
+++ b/src/Tests.Unit/Tests.Unit.csproj
@@ -5,12 +5,16 @@
+
+
+
+