Implementing a Library Like MediatR-Notification in .NET Core
Table of contents
In this article, we will look at how to create a notification library in .NET Core inspired by the popular MediatR library. We will start by defining the core interfaces that make up the notification system, and then we will build a mediator class that can handle and dispatches notifications to the appropriate handlers. Finally, we will see how to use dependency injection to register and use the notification system in a .NET Core application.
You can find the source code for the MediatR-inspired notification library and the complete project on my GitHub page at the following link:
https://github.com/vamcan/MyMediatR-Notification
First, create a class called
INotification
that serves as the base interface for all notifications. This interface should not have any method:public interface INotification { }
Next, create a generic interface called
INotificationHandler<T>
that defines a single method,Handle
, that takes aT
(which should be anINotification
) as an argument:public interface INotificationHandler<in T> where T : INotification { Task Handle(T notification); }
You can then create concrete implementations of
INotification
by defining classes that implement theINotification
interface. For example:public class UserCreatedNotification : INotification { public string Email { get; set; } public string Password { get; set; } }
You can also create concrete implementations of
INotificationHandler<T>
by defining classes that implement theINotificationHandler<T>
interface. For example:public class UserCreatedNotificationHandler : INotificationHandler<UserCreatedNotification> { public async Task Handle(UserCreatedNotification notification) { // Perform some action when a UserCreatedNotification is received } }
Finally, you can create an interface and class that serve as a central "mediator" for handling notifications. This class should have a method for registering
INotificationHandler<T>
implementations and a method for publishingINotification
objects to be handled:```csharp
public interface INotificationMediator { void Register<T>(INotificationHandler<T> handler) where T : INotification; Task Publish<T>(T notification) where T : INotification; }
public class NotificationMediator : INotificationMediator
{
private readonly ConcurrentDictionary<Type, List<object>> _handlers = new ConcurrentDictionary<Type, List<object>>();
public void Register<T>(INotificationHandler<T> handler) where T : INotification
{
var notificationType = typeof(T);
if (!_handlers.ContainsKey(notificationType))
{
_handlers[notificationType] = new List<object>();
}
_handlers[notificationType].Add(handler);
}
public async Task Publish<T>(T notification) where T : INotification
{
var notificationType = typeof(T);
if (_handlers.ContainsKey(notificationType))
{
foreach (INotificationHandler<T> handler in _handlers[notificationType])
{
await handler.Handle(notification);
}
}
}
}
```
- You can then use the
NotificationMediator
class to registerINotificationHandler<T>
implementations and publishINotification
objects as follows:
// Create a notification mediator
var mediator = new NotificationMediator();
// Register a notification handler
mediator.Register(new UserCreatedNotificationHandler());
// Create and publish a notification
await mediator.Publish(new UserCreatedNotification
{
Email = "Reza@example.com",
Password = "password"
});
This code will create a new NotificationMediator
and register an instance of UserCreatedNotificationHandler
with it. Then, it will create a new UserCreatedNotification
and publish it to the mediator, which will in turn call the Handle
method on the registered UserCreatedNotificationHandler
instance.
you might want register your notification library as a service in the ConfigureServices
method of your Startup
class and scan for and register all INotificationHandler<T>
implementations in an assembly :
public static void AddMyNotificationMediator(this IServiceCollection services, Assembly assembly)
{
var notificationMediator = new NotificationMediator();
var notificationHandlerTypes = assembly
.GetExportedTypes()
.Where(x => x.GetInterfaces().Any(y => y.IsGenericType && y.GetGenericTypeDefinition() == typeof(INotificationHandler<>)));
foreach (var notificationHandlerType in notificationHandlerTypes)
{
var notificationType = notificationHandlerType.GetInterfaces().First().GetGenericArguments().First();
var registerMethod = typeof(NotificationMediator).GetMethod("Register").MakeGenericMethod(notificationType);
registerMethod.Invoke(notificationMediator, new object[] { Activator.CreateInstance(notificationHandlerType) });
}
services.AddSingleton<INotificationMediator>(notificationMediator);
}
This code will register your NotificationMediator
as a singleton service, and will find all types in the specified assembly that implement INotificationHandler<T>
and register them
Then you should register it in Program.cs
// Get the assembly that contains your notification handlers
var assembly = Assembly.GetExecutingAssembly();
//Register Our Service
builder.Services.AddMyNotificationMediator(assembly);
You can then inject the INotificationMediator
into your controllers or other classes using dependency injection:
public class SomeController : Controller
{
private readonly NotificationMediator _mediator;
public SomeController(NotificationMediator mediator)
{
_mediator = mediator;
}
[HttpGet("SendNotification")]
public async Task<IActionResult> SendNotification()
{
// Create and publish a notification
await _mediator.Publish(new UserCreatedNotification
{
Email = "Reza@example.com",
Password = "password"
});
return Ok();
}
}
You can find the source code for the MediatR-inspired notification library and the complete project on my GitHub page at the following link:
https://github.com/vamcan/MyMediatR-Notification
Please give it a star if you found it useful :)
Let me know if you have any questions. :)
Subscribe to my newsletter
Read articles from reza ghasemi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
reza ghasemi
reza ghasemi
As a software developer with hands-on experience in back-end development using C# and .NET Core frameworks, and familiar with front-end development using JavaScript, Angular, and ReactJS, I possess a strong foundation in system development and architecture. Throughout my career, I have developed and designed software for various types of businesses, predominantly in a back-end capacity but also as a full-stack developer. My technical expertise includes C#, ASP.NET MVC, ASP.NET Core, SQL, NoSQL, T-SQL, JavaScript, Angular and React. Additionally, I have a solid understanding of key concepts such as SOLID principles, object-oriented programming, domain-driven design, test-driven development, continuous integration and deployment, and microservices. These skills, combined with my ability to adapt to new technologies and techniques, make me well-equipped to tackle a wide range of software development challenges.