From 53ab9f3b16868226a8ba22f206f90cf6dad426fb Mon Sep 17 00:00:00 2001 From: Duke <40759437+dukesteen@users.noreply.github.com> Date: Tue, 5 Apr 2022 19:18:25 +0200 Subject: [PATCH] MediatR Guide + sample (#2218) * Add guide for MediatR * Add sample for MediatR * Fix exposed token in program.cs * Fix review points * Remove newline in MediatrDiscordEventListener.cs --- .../other_libs/images/mediatr_output.png | Bin 0 -> 24076 bytes docs/guides/other_libs/mediatr.md | 70 +++++++++++++++++ .../samples/MediatrConfiguringDI.cs | 1 + .../MediatrCreatingMessageNotification.cs | 16 ++++ .../samples/MediatrDiscordEventListener.cs | 46 +++++++++++ .../samples/MediatrMessageReceivedHandler.cs | 17 ++++ .../samples/MediatrStartListener.cs | 4 + docs/guides/toc.yml | 2 + samples/MediatRSample/MediatRSample.sln | 16 ++++ .../MediatRSample/DiscordEventListener.cs | 48 ++++++++++++ .../Handlers/MessageReceivedHandler.cs | 14 ++++ .../MediatRSample/MediatRSample.csproj | 20 +++++ .../MessageReceivedNotification.cs | 14 ++++ .../Notifications/ReadyNotification.cs | 13 ++++ .../MediatRSample/MediatRSample/Program.cs | 73 ++++++++++++++++++ 15 files changed, 354 insertions(+) create mode 100644 docs/guides/other_libs/images/mediatr_output.png create mode 100644 docs/guides/other_libs/mediatr.md create mode 100644 docs/guides/other_libs/samples/MediatrConfiguringDI.cs create mode 100644 docs/guides/other_libs/samples/MediatrCreatingMessageNotification.cs create mode 100644 docs/guides/other_libs/samples/MediatrDiscordEventListener.cs create mode 100644 docs/guides/other_libs/samples/MediatrMessageReceivedHandler.cs create mode 100644 docs/guides/other_libs/samples/MediatrStartListener.cs create mode 100644 samples/MediatRSample/MediatRSample.sln create mode 100644 samples/MediatRSample/MediatRSample/DiscordEventListener.cs create mode 100644 samples/MediatRSample/MediatRSample/Handlers/MessageReceivedHandler.cs create mode 100644 samples/MediatRSample/MediatRSample/MediatRSample.csproj create mode 100644 samples/MediatRSample/MediatRSample/Notifications/MessageReceivedNotification.cs create mode 100644 samples/MediatRSample/MediatRSample/Notifications/ReadyNotification.cs create mode 100644 samples/MediatRSample/MediatRSample/Program.cs diff --git a/docs/guides/other_libs/images/mediatr_output.png b/docs/guides/other_libs/images/mediatr_output.png new file mode 100644 index 0000000000000000000000000000000000000000..801809313bb553421b5902fd23072b075960bf48 GIT binary patch literal 24076 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 wUO70h+~}B`qtEBpCCdK)AJ(`PJ$r>ci` interface provided by MediatR, this tells MediatR to dispatch `MessageReceivedNotification` notifications to this handler class. + +> [!NOTE] +> You can create as many notification handlers for the same notification as you desire. That's the beauty of MediatR! + +## Testing + +To test if we have successfully implemented MediatR, we can start up the bot and send a message to a server the bot is in. It should print out the message we defined earlier in our `MessageReceivedHandler`. + +![MediatR output](images/mediatr_output.png) + +## Adding more event types + +To add more event types you can follow these steps: + +1. Create a new notification class for the event. it should contain all of the parameters that the event would send. (Ex: the `MessageReceived` event takes one `SocketMessage` as an argument. The notification class should also map this argument) +2. Register the event in your `DiscordEventListener` class. +3. Create a notification handler for your new notification. diff --git a/docs/guides/other_libs/samples/MediatrConfiguringDI.cs b/docs/guides/other_libs/samples/MediatrConfiguringDI.cs new file mode 100644 index 000000000..3bef7bd76 --- /dev/null +++ b/docs/guides/other_libs/samples/MediatrConfiguringDI.cs @@ -0,0 +1 @@ +.AddMediatR(typeof(Bot)) diff --git a/docs/guides/other_libs/samples/MediatrCreatingMessageNotification.cs b/docs/guides/other_libs/samples/MediatrCreatingMessageNotification.cs new file mode 100644 index 000000000..449c96eb4 --- /dev/null +++ b/docs/guides/other_libs/samples/MediatrCreatingMessageNotification.cs @@ -0,0 +1,16 @@ +// MessageReceivedNotification.cs + +using Discord.WebSocket; +using MediatR; + +namespace MediatRSample.Notifications; + +public class MessageReceivedNotification : INotification +{ + public MessageReceivedNotification(SocketMessage message) + { + Message = message ?? throw new ArgumentNullException(nameof(message)); + } + + public SocketMessage Message { get; } +} diff --git a/docs/guides/other_libs/samples/MediatrDiscordEventListener.cs b/docs/guides/other_libs/samples/MediatrDiscordEventListener.cs new file mode 100644 index 000000000..09583c3e9 --- /dev/null +++ b/docs/guides/other_libs/samples/MediatrDiscordEventListener.cs @@ -0,0 +1,46 @@ +// DiscordEventListener.cs + +using Discord.WebSocket; +using MediatR; +using MediatRSample.Notifications; +using Microsoft.Extensions.DependencyInjection; +using System.Threading; +using System.Threading.Tasks; + +namespace MediatRSample; + +public class DiscordEventListener +{ + private readonly CancellationToken _cancellationToken; + + private readonly DiscordSocketClient _client; + private readonly IServiceScopeFactory _serviceScope; + + public DiscordEventListener(DiscordSocketClient client, IServiceScopeFactory serviceScope) + { + _client = client; + _serviceScope = serviceScope; + _cancellationToken = new CancellationTokenSource().Token; + } + + private IMediator Mediator + { + get + { + var scope = _serviceScope.CreateScope(); + return scope.ServiceProvider.GetRequiredService(); + } + } + + public async Task StartAsync() + { + _client.MessageReceived += OnMessageReceivedAsync; + + await Task.CompletedTask; + } + + private Task OnMessageReceivedAsync(SocketMessage arg) + { + return Mediator.Publish(new MessageReceivedNotification(arg), _cancellationToken); + } +} diff --git a/docs/guides/other_libs/samples/MediatrMessageReceivedHandler.cs b/docs/guides/other_libs/samples/MediatrMessageReceivedHandler.cs new file mode 100644 index 000000000..1ab2491e2 --- /dev/null +++ b/docs/guides/other_libs/samples/MediatrMessageReceivedHandler.cs @@ -0,0 +1,17 @@ +// MessageReceivedHandler.cs + +using System; +using MediatR; +using MediatRSample.Notifications; + +namespace MediatRSample; + +public class MessageReceivedHandler : INotificationHandler +{ + public async Task Handle(MessageReceivedNotification notification, CancellationToken cancellationToken) + { + Console.WriteLine($"MediatR works! (Received a message by {notification.Message.Author.Username})"); + + // Your implementation + } +} diff --git a/docs/guides/other_libs/samples/MediatrStartListener.cs b/docs/guides/other_libs/samples/MediatrStartListener.cs new file mode 100644 index 000000000..72a54bf25 --- /dev/null +++ b/docs/guides/other_libs/samples/MediatrStartListener.cs @@ -0,0 +1,4 @@ +// Program.cs + +var listener = services.GetRequiredService(); +await listener.StartAsync(); diff --git a/docs/guides/toc.yml b/docs/guides/toc.yml index b1a6b4721..af0a8e2b4 100644 --- a/docs/guides/toc.yml +++ b/docs/guides/toc.yml @@ -115,6 +115,8 @@ topicUid: Guides.OtherLibs.Serilog - name: EFCore topicUid: Guides.OtherLibs.EFCore + - name: MediatR + topicUid: Guides.OtherLibs.MediatR - name: Emoji topicUid: Guides.Emoji - name: Voice diff --git a/samples/MediatRSample/MediatRSample.sln b/samples/MediatRSample/MediatRSample.sln new file mode 100644 index 000000000..d0599ae26 --- /dev/null +++ b/samples/MediatRSample/MediatRSample.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediatRSample", "MediatRSample\MediatRSample.csproj", "{CE066EE5-7ED1-42A0-8DB2-862D44F40EA7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CE066EE5-7ED1-42A0-8DB2-862D44F40EA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE066EE5-7ED1-42A0-8DB2-862D44F40EA7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE066EE5-7ED1-42A0-8DB2-862D44F40EA7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE066EE5-7ED1-42A0-8DB2-862D44F40EA7}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/samples/MediatRSample/MediatRSample/DiscordEventListener.cs b/samples/MediatRSample/MediatRSample/DiscordEventListener.cs new file mode 100644 index 000000000..dec342773 --- /dev/null +++ b/samples/MediatRSample/MediatRSample/DiscordEventListener.cs @@ -0,0 +1,48 @@ +using Discord.WebSocket; +using MediatR; +using MediatRSample.Notifications; +using Microsoft.Extensions.DependencyInjection; + +namespace MediatRSample; + +public class DiscordEventListener +{ + private readonly CancellationToken _cancellationToken; + + private readonly DiscordSocketClient _client; + private readonly IServiceScopeFactory _serviceScope; + + public DiscordEventListener(DiscordSocketClient client, IServiceScopeFactory serviceScope) + { + _client = client; + _serviceScope = serviceScope; + _cancellationToken = new CancellationTokenSource().Token; + } + + private IMediator Mediator + { + get + { + var scope = _serviceScope.CreateScope(); + return scope.ServiceProvider.GetRequiredService(); + } + } + + public Task StartAsync() + { + _client.Ready += OnReadyAsync; + _client.MessageReceived += OnMessageReceivedAsync; + + return Task.CompletedTask; + } + + private Task OnMessageReceivedAsync(SocketMessage arg) + { + return Mediator.Publish(new MessageReceivedNotification(arg), _cancellationToken); + } + + private Task OnReadyAsync() + { + return Mediator.Publish(ReadyNotification.Default, _cancellationToken); + } +} \ No newline at end of file diff --git a/samples/MediatRSample/MediatRSample/Handlers/MessageReceivedHandler.cs b/samples/MediatRSample/MediatRSample/Handlers/MessageReceivedHandler.cs new file mode 100644 index 000000000..5cae3f267 --- /dev/null +++ b/samples/MediatRSample/MediatRSample/Handlers/MessageReceivedHandler.cs @@ -0,0 +1,14 @@ +using MediatR; +using MediatRSample.Notifications; + +namespace MediatRSample.Handlers; + +public class MessageReceivedHandler : INotificationHandler +{ + public async Task Handle(MessageReceivedNotification notification, CancellationToken cancellationToken) + { + Console.WriteLine($"MediatR works! (Received a message by {notification.Message.Author.Username})"); + + // Your implementation + } +} \ No newline at end of file diff --git a/samples/MediatRSample/MediatRSample/MediatRSample.csproj b/samples/MediatRSample/MediatRSample/MediatRSample.csproj new file mode 100644 index 000000000..4e9d01c8c --- /dev/null +++ b/samples/MediatRSample/MediatRSample/MediatRSample.csproj @@ -0,0 +1,20 @@ + + + + Exe + net6.0 + enable + enable + Linux + + + + + + + + + + + + diff --git a/samples/MediatRSample/MediatRSample/Notifications/MessageReceivedNotification.cs b/samples/MediatRSample/MediatRSample/Notifications/MessageReceivedNotification.cs new file mode 100644 index 000000000..610b4a0a5 --- /dev/null +++ b/samples/MediatRSample/MediatRSample/Notifications/MessageReceivedNotification.cs @@ -0,0 +1,14 @@ +using Discord.WebSocket; +using MediatR; + +namespace MediatRSample.Notifications; + +public class MessageReceivedNotification : INotification +{ + public MessageReceivedNotification(SocketMessage message) + { + Message = message ?? throw new ArgumentNullException(nameof(message)); + } + + public SocketMessage Message { get; } +} \ No newline at end of file diff --git a/samples/MediatRSample/MediatRSample/Notifications/ReadyNotification.cs b/samples/MediatRSample/MediatRSample/Notifications/ReadyNotification.cs new file mode 100644 index 000000000..bafa6c10b --- /dev/null +++ b/samples/MediatRSample/MediatRSample/Notifications/ReadyNotification.cs @@ -0,0 +1,13 @@ +using MediatR; + +namespace MediatRSample.Notifications; + +public class ReadyNotification : INotification +{ + public static readonly ReadyNotification Default + = new(); + + private ReadyNotification() + { + } +} \ No newline at end of file diff --git a/samples/MediatRSample/MediatRSample/Program.cs b/samples/MediatRSample/MediatRSample/Program.cs new file mode 100644 index 000000000..96b393e5d --- /dev/null +++ b/samples/MediatRSample/MediatRSample/Program.cs @@ -0,0 +1,73 @@ +using Discord; +using Discord.Interactions; +using Discord.WebSocket; +using MediatR; +using Microsoft.Extensions.DependencyInjection; +using Serilog; +using Serilog.Events; + +namespace MediatRSample; + +public class Bot +{ + private static ServiceProvider ConfigureServices() + { + return new ServiceCollection() + .AddMediatR(typeof(Bot)) + .AddSingleton(new DiscordSocketClient(new DiscordSocketConfig + { + AlwaysDownloadUsers = true, + MessageCacheSize = 100, + GatewayIntents = GatewayIntents.AllUnprivileged, + LogLevel = LogSeverity.Info + })) + .AddSingleton() + .AddSingleton(x => new InteractionService(x.GetRequiredService())) + .BuildServiceProvider(); + } + + public static async Task Main() + { + await new Bot().RunAsync(); + } + + private async Task RunAsync() + { + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Verbose() + .Enrich.FromLogContext() + .WriteTo.Console() + .CreateLogger(); + + await using var services = ConfigureServices(); + + var client = services.GetRequiredService(); + client.Log += LogAsync; + + var listener = services.GetRequiredService(); + await listener.StartAsync(); + + await client.LoginAsync(TokenType.Bot, "YOUR_TOKEN_HERE"); + await client.StartAsync(); + + await Task.Delay(Timeout.Infinite); + } + + private static Task LogAsync(LogMessage message) + { + var severity = message.Severity switch + { + LogSeverity.Critical => LogEventLevel.Fatal, + LogSeverity.Error => LogEventLevel.Error, + LogSeverity.Warning => LogEventLevel.Warning, + LogSeverity.Info => LogEventLevel.Information, + LogSeverity.Verbose => LogEventLevel.Verbose, + LogSeverity.Debug => LogEventLevel.Debug, + _ => LogEventLevel.Information + }; + + Log.Write(severity, message.Exception, "[{Source}] {Message}", message.Source, message.Message); + + return Task.CompletedTask; + } +}