Skip to content

Commit 3111a69

Browse files
feat: add Multiple Notification support
1 parent c5c5c67 commit 3111a69

9 files changed

Lines changed: 149 additions & 9 deletions

CommandQuery/CommandQuery.csproj

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
<Nullable>enable</Nullable>
77
<Features>strict</Features>
88
<Authors>Ros Sokcheanith</Authors>
9-
<Description>Simple, unambitious mediator CQRS implementation in .NET</Description>
9+
<Description>Simple, unambitious CQRS implementation in .NET</Description>
1010
<Copyright>Copyright Ros Sokcheanith</Copyright>
11-
<PackageTags>mediator;request;response;queries;commands;notifications</PackageTags>
11+
<PackageTags>request;response;queries;commands;notifications</PackageTags>
1212
<PackageReadmeFile>README.md</PackageReadmeFile>
1313
<SignAssembly>true</SignAssembly>
1414
<AssemblyOriginatorKeyFile>..\CommandQuery.snk</AssemblyOriginatorKeyFile>
@@ -23,7 +23,8 @@
2323
<Deterministic>true</Deterministic>
2424
<ContinuousIntegrationBuild Condition="'$(GITHUB_ACTIONS)' == 'true'">true</ContinuousIntegrationBuild>
2525
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
26-
<Title>BAS24.Libs</Title>
26+
<Title>CommandQuery</Title>
27+
<PackageId>CommandQuery</PackageId>
2728
<PackageProjectUrl>https://github.com/codewithmecoder/CommandQuery</PackageProjectUrl>
2829
<RepositoryUrl>https://github.com/codewithmecoder/CommandQuery</RepositoryUrl>
2930
</PropertyGroup>

CommandQuery/Notifications/INotification.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,9 @@
33
/// <summary>
44
/// INotification interface for notifications in the CommandQuery library.
55
/// </summary>
6-
public interface INotification;
6+
public interface INotification;
7+
8+
/// <summary>
9+
/// IPriorityNotification priority interface for notifications in the CommandQuery library.
10+
/// </summary>
11+
public interface IPriorityNotification : INotification;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace CommandQuery.Notifications;
2+
3+
/// <summary>
4+
/// For execute parallel notification
5+
/// </summary>
6+
public interface IParallelNotification : INotification;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace CommandQuery.Notifications;
2+
3+
/// <summary>
4+
///
5+
/// </summary>
6+
/// <typeparam name="TNotification"></typeparam>
7+
public interface IPriorityNotificationHandler<in TNotification>
8+
: INotificationHandler<TNotification>
9+
where TNotification : IPriorityNotification
10+
{
11+
/// <summary>
12+
///
13+
/// </summary>
14+
public int Priority { get; }
15+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
namespace CommandQuery.Notifications;
2+
3+
/// <summary>
4+
///
5+
/// </summary>
6+
public class MultipleNotificationPublisher : INotificationPublisher
7+
{
8+
private readonly TaskWhenAllPublisher _taskWhenAllPublisher = new();
9+
private readonly ForeachAwaitPublisher _foreachAwaitPublisher = new();
10+
private readonly PriorityNotificationPublisher _priorityNotificationPublisher = new();
11+
12+
/// <summary>
13+
///
14+
/// </summary>
15+
/// <param name="handlerExecutors"></param>
16+
/// <param name="notification"></param>
17+
/// <param name="cancellationToken"></param>
18+
/// <returns></returns>
19+
public async Task Publish(
20+
IEnumerable<NotificationHandlerExecutor> handlerExecutors,
21+
INotification notification,
22+
CancellationToken cancellationToken
23+
)
24+
{
25+
switch (notification)
26+
{
27+
case IPriorityNotification:
28+
await _priorityNotificationPublisher.Publish(handlerExecutors, notification, cancellationToken);
29+
break;
30+
case IParallelNotification:
31+
await _taskWhenAllPublisher
32+
.Publish(handlerExecutors, notification, cancellationToken)
33+
.ConfigureAwait(false);
34+
break;
35+
default:
36+
await _foreachAwaitPublisher.Publish(handlerExecutors, notification, cancellationToken);
37+
break;
38+
}
39+
}
40+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
namespace CommandQuery.Notifications;
2+
3+
/// <summary>
4+
///
5+
/// </summary>
6+
public class PriorityNotificationPublisher : INotificationPublisher
7+
{
8+
private const int DefaultPriority = 99;
9+
10+
/// <summary>
11+
///
12+
/// </summary>
13+
/// <param name="handlerExecutors"></param>
14+
/// <param name="notification"></param>
15+
/// <param name="cancellationToken"></param>
16+
/// <returns></returns>
17+
public async Task Publish(
18+
IEnumerable<NotificationHandlerExecutor> handlerExecutors,
19+
INotification notification,
20+
CancellationToken cancellationToken
21+
)
22+
{
23+
var lookUp = handlerExecutors
24+
.ToLookup(key => GetPriority(key.HandlerInstance), value => value)
25+
.OrderBy(k => k.Key);
26+
27+
foreach (var handler in lookUp)
28+
{
29+
foreach (var notificationHandler in handler.ToList())
30+
{
31+
await notificationHandler
32+
.HandlerCallback(notification, cancellationToken)
33+
.ConfigureAwait(false);
34+
}
35+
}
36+
}
37+
38+
private static int GetPriority(object handler)
39+
{
40+
var priority = handler
41+
.GetType()
42+
.GetProperties().ToList()
43+
.Find(t =>
44+
t.Name == nameof(IPriorityNotificationHandler<IPriorityNotification>.Priority)
45+
);
46+
47+
return priority == null ? DefaultPriority : int.Parse(priority.GetValue(handler)?.ToString() ?? DefaultPriority.ToString());
48+
}
49+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
namespace CommandQuery.Notifications;
2+
3+
/// <summary>
4+
///
5+
/// </summary>
6+
public class TaskWhenAllPublisher : INotificationPublisher
7+
{
8+
/// <summary>
9+
///
10+
/// </summary>
11+
/// <param name="handlerExecutors"></param>
12+
/// <param name="notification"></param>
13+
/// <param name="cancellationToken"></param>
14+
/// <returns></returns>
15+
public Task Publish(IEnumerable<NotificationHandlerExecutor> handlerExecutors, INotification notification, CancellationToken cancellationToken)
16+
{
17+
var tasks = handlerExecutors
18+
.Select(handler => handler.HandlerCallback(notification, cancellationToken))
19+
.ToArray();
20+
21+
return Task.WhenAll(tasks);
22+
}
23+
}

Sample/Program.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using CommandQuery;
2+
using CommandQuery.Notifications;
23
using Sample;
34

45
var builder = WebApplication.CreateBuilder(args);
@@ -29,9 +30,9 @@
2930
builder.Services.AddCommandQuery(cq =>
3031
{
3132
cq.RegisterAssembly(typeof(Program).Assembly);
32-
//cq.NotificationPublisher = new MultipleNotificationPublisher();
33-
//cq.NotificationPublisherType = typeof(MultipleNotificationPublisher);
34-
33+
cq.NotificationPublisher = new MultipleNotificationPublisher();
34+
cq.NotificationPublisherType = typeof(MultipleNotificationPublisher);
35+
3536
cq.AddBehavior(typeof(LoggingPipelineBehavior<,>));
3637
cq.AddRequestPreProcessor(typeof(GenericRequestPreProcessor<>));
3738
cq.AddRequestPostProcessor(typeof(GenericRequestPostProcessor<,>));

Sample/UserCreatedNotification.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class EmailService(ILogger<EmailService> logger) : IEmailService
1111
{
1212
public Task SendWelcomeEmailAsync(Guid notificationUserId, string notificationName)
1313
{
14-
logger.LogDebug("EmailService: Sending welcome email to {notificationName} with ID {notificationUserId}", notificationName, notificationUserId);
14+
logger.LogDebug("EmailService: Sending welcome email to {NotificationName} with ID {NotificationUserId}", notificationName, notificationUserId);
1515
return Task.CompletedTask;
1616
}
1717
}
@@ -24,7 +24,7 @@ public class SmsService(ILogger<SmsService> logger) : ISmsService
2424
{
2525
public Task SendWelcomeSmsAsync(Guid notificationUserId, string notificationName)
2626
{
27-
logger.LogDebug("SmsService: Sending welcome SMS to {notificationName} with ID {notificationUserId}", notificationName, notificationUserId);
27+
logger.LogDebug("SmsService: Sending welcome SMS to {NotificationName} with ID {NotificationUserId}", notificationName, notificationUserId);
2828
return Task.CompletedTask;
2929
}
3030
}

0 commit comments

Comments
 (0)