Skip to content

A lightweight and minimal mediator library for .NET. Interlink helps you decouple your application using request/response and notification patterns with simple, clean code.

License

Notifications You must be signed in to change notification settings

manusoft/Interlink-cqrs-library

Repository files navigation

Static Badge NuGet Version NuGet Downloads .NET

Interlink

Interlink is a lightweight and modern mediator library for .NET, designed to decouple your code through request/response and notification patterns. Built with simplicity and performance in mind, it helps streamline communication between components while maintaining a clean architecture.

ChatGPT Image Apr 16, 2025, 12_32_44 AM (Custom)


✨ Features

  • 🧩 Simple mediator pattern for request/response
  • πŸ” Publish/Subscribe notification system
  • πŸ”§ Pipeline behaviors (logging, validation, etc.)
  • 🧠 Clean separation of concerns via handlers
  • πŸͺ Dependency injection support out of the box
  • πŸ”„ Decouples logic using handlers
  • 🧩 Easy registration with AddInterlink()
  • πŸš€ Lightweight, fast, and no external dependencies
  • πŸ”„ Pre and Post Processors for enhanced lifecycle control
  • βœ… Compatible with .NET 8 and .NET 9
  • πŸ” Assembly scanning for automatic handler registration
  • πŸ§ͺ Custom service factory injection
  • πŸ”„ Pipeline ordering via attributes or configuration
  • πŸ”„ Handler resolution caching (delegate-based)

πŸ’‘ Why Interlink?

  • Clean, intuitive API
  • No bloat – just powerful mediation
  • Perfect for CQRS, Clean Architecture, Modular Design
  • Highly extensible with behaviors and notifications

πŸ“¦ Installation

Install Interlink via NuGet:

dotnet add package Interlink

βš™οΈ Setup

Register Interlink in your Startup.cs or Program.cs

builder.Services.AddInterlink();

You can optionally pass an Assembly:

builder.Services.AddInterlink(typeof(MyHandler).Assembly);

πŸ“¨ Request/Response Pattern

1. Define a request:

public class GetAllPets
{
    public record Query : IRequest<List<string>>;

    public class Handler : IRequestHandler<Query, List<string>>
    {
        public Task<List<string>> Handle(Query request, CancellationToken cancellationToken)
        {
            var pets = new List<string> { "Dog", "Cat", "Fish" };
            return Task.FromResult(pets);
        }
    }
}

2. Inject and use ISender:

[ApiController]
[Route("api/[controller]")]
public class PetController(ISender sender) : ControllerBase
{
    [HttpGet]
    public async Task<IActionResult> GetAllPets(CancellationToken cancellationToken)
    {
        var pets = await sender.Send(new GetAllPets.Query(), cancellationToken);
        return Ok(pets);
    }
}

πŸ“£ Notifications (One-to-Many)

1. Define a notification:

public class UserCreated(string userName) : INotification
{
    public string UserName { get; } = userName;
}

2. Create one or more handlers:

public class SendWelcomeEmail : INotificationHandler<UserCreated>
{
    public Task Handle(UserCreated notification, CancellationToken cancellationToken)
    {
        Console.WriteLine($"Welcome email sent to {notification.UserName}");
        return Task.CompletedTask;
    }
}

3. Publish with IPublisher:

public class AccountService(IPublisher publisher)
{
    public async Task RegisterUser(string username)
    {
        // Save to DB...
        await publisher.Publish(new UserCreated(username));
    }
}

🧬 Pipeline Behaviors

Useful for logging, validation, performance monitoring, etc.

1. Define a behavior:

public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
    {
        Console.WriteLine($"Handling {typeof(TRequest).Name}");
        var response = await next();
        Console.WriteLine($"Handled {typeof(TRequest).Name}");
        return response;
    }
}

Pipeline behaviors can be manually registered like this:

builder.Services.AddInterlink(config =>
{
    config.AddBehavior(typeof(LoggingBehavior<,>));
    config.AddBehavior(typeof(LoggingBehavior2<,>)); // Add more behaviors as needed
});

Pipeline ordering can be controlled via attributes or configuration.

[PipelineOrder(1)]
public class FirstBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
    {
        Console.WriteLine("First behavior executed");
        return await next();
    }
}

[PipelineOrder(2)]
public class SecondBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
    {
        Console.WriteLine("Second behavior executed");
        return await next();
    }
}

You can also use the AddInterlink() method to specify the order of pipeline behaviors:

builder.Services.AddInterlink(config =>
{
    config.AddBehavior(typeof(FirstBehavior<,>));
    config.AddBehavior(typeof(SecondBehavior<,>));
});

πŸ”„ Pre and Post Processor

1. Define Pre and Post Processors:

public class MyRequestPreProcessor : IRequestPreProcessor<GetAllPets.Query>
{
    public Task Process(GetAllPets.Query request, CancellationToken cancellationToken)
    {
        Console.WriteLine("[PreProcessor] Processing GetAllPets request...");
        return Task.CompletedTask;
    }
}

public class MyRequestPostProcessor : IRequestPostProcessor<GetAllPets.Query, List<Pet>>
{
    public Task Process(GetAllPets.Query request, List<Pet> response, CancellationToken cancellationToken)
    {
        Console.WriteLine("[PostProcessor] Processing GetAllPets response...");
        return Task.CompletedTask;
    }
}

Pre and Post Processors are automatically registered when you call AddInterlink().


πŸ“¦ API Overview

IRequest<TResponse>

public interface IRequest<TResponse> { }

IRequestHandler<TRequest, TResponse>

public interface IRequestHandler<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken);
}

INotification

public interface INotification { }

INotificationHandler<TNotification>

public interface INotificationHandler<TNotification>
    where TNotification : INotification
{
    Task Handle(TNotification notification, CancellationToken cancellationToken);
}

ISender

public interface ISender
{
    Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default);
}

IPublisher

public interface IPublisher
{
    Task Publish<TNotification>(TNotification notification, CancellationToken cancellationToken = default)
        where TNotification : INotification;
}

IPipelineBehavior<TRequest, TResponse>

public delegate Task<TResponse> RequestHandlerDelegate<TResponse>();

public interface IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next);
}

IRequestPreProcessor<TRequest>

public interface IRequestPreProcessor<TRequest>
{
    Task Process(TRequest request, CancellationToken cancellationToken);
}

IRequestPostProcessor<TRequest, TResponse>

public interface IRequestPostProcessor<TRequest, TResponse>
{
    Task Process(TRequest request, TResponse response, CancellationToken cancellationToken);
}

πŸ” Example Use Case

  • CQRS: Use IRequest<TResponse> for Queries and Commands
  • Event-Driven architecture: Use INotification for broadcasting domain events
  • Middleware-style behaviors: Add IPipelineBehavior for logging, validation, caching, etc.

πŸš€ Roadmap

βœ… v1.0.0 β€” Core Mediator Basics (Released)

  • Basic IRequest<TResponse> and IRequestHandler<TRequest, TResponse>
  • ISender for sending requests
  • AddInterlink() for automatic DI registration
  • Clean, lightweight design
  • Only .NET 9 support

βœ… v1.0.1 β€” Core Mediator Basics (Released)

  • Basic IRequest<TResponse> and IRequestHandler<TRequest, TResponse>
  • ISender for sending requests
  • AddInterlink() for automatic DI registration
  • Clean, lightweight design
  • .NET 8+ support

βœ… v1.1.0 β€” Notifications & Pipelines (Released)

  • INotification and INotificationHandler<TNotification>
  • IPublisher for event broadcasting
  • IPipelineBehavior<TRequest, TResponse> support
  • Enhanced AddInterlink() with scanning and registration for notifications and pipelines
  • Updated documentation and examples
  • .NET 8+ support

βœ… v1.2.0 β€” Pre/Post Processors (Released)

  • IRequestPreProcessor<TRequest> interface
  • IRequestPostProcessor<TRequest, TResponse> interface
  • Pre and post hooks for request lifecycle
  • Optional unit-of-work behaviors

βœ… v1.2.1 β€” Fix Critical Bugs (Released)

  • Fix critical bugs in IPipelineBehavior<TRequest, TResponse>

βœ… v1.3.0 β€” Performance & Customization (Released)

  • Handler resolution caching (delegate-based)
  • Custom service factory injection support
  • Pipeline ordering via attributes or configuration
  • Assembly scanning filters by namespace or attribute

🌐 v1.4.0 β€” Extensions

  • Interlink.Extensions.Logging β€” built-in logging behavior
  • Interlink.Extensions.Validation β€” integration with FluentValidation
  • Interlink.AspNetCore β€” model binding & filters for ASP.NET Core

πŸ§ͺ v1.5.0 β€” Developer Experience

  • Source generator / Roslyn analyzer for missing handler detection
  • Code snippets and templates for common patterns
  • Custom exception types (e.g., HandlerNotFoundException)

πŸ“… Future Ideas

  • Request cancellation and timeout behaviors
  • Metrics collection and tracing support
  • Dynamic or externalized pipeline config (e.g., JSON-based)

Stay tuned for more updates! Contributions and suggestions are welcome. ✨

πŸ“œ License

MIT License Β© ManuHub


About

A lightweight and minimal mediator library for .NET. Interlink helps you decouple your application using request/response and notification patterns with simple, clean code.

Topics

Resources

License

Stars

Watchers

Forks

Languages