Implementing a Library Like MediatR-Notification in .NET Core

Implementing a Library Like MediatR-Notification in .NET Core

Table of contents

No heading

No headings in the article.

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:

github.com/vamcan/MyMediatR-Notification

  1. 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
     {
     }
    
  2. Next, create a generic interface called INotificationHandler<T> that defines a single method, Handle, that takes a T (which should be an INotification) as an argument:

     public interface INotificationHandler<in T> where T : INotification
     {
         Task Handle(T notification);
     }
    
  3. You can then create concrete implementations of INotification by defining classes that implement the INotification interface. For example:

     public class UserCreatedNotification : INotification
     {
         public string Email { get; set; }
         public string Password { get; set; }
     }
    
  4. You can also create concrete implementations of INotificationHandler<T> by defining classes that implement the INotificationHandler<T> interface. For example:

     public class UserCreatedNotificationHandler : INotificationHandler<UserCreatedNotification>
     {
         public async Task Handle(UserCreatedNotification notification)
         {
             // Perform some action when a UserCreatedNotification is received
         }
     }
    
  5. 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 publishing INotification 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);
                }
            }
        }
    }
```
  1. You can then use the NotificationMediator class to register INotificationHandler<T> implementations and publish INotification 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. :)

Did you find this article valuable?

Support Reza Ghasemi by becoming a sponsor. Any amount is appreciated!