Interlink 1.5.0

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package Interlink --version 1.5.0
                    
NuGet\Install-Package Interlink -Version 1.5.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Interlink" Version="1.5.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Interlink" Version="1.5.0" />
                    
Directory.Packages.props
<PackageReference Include="Interlink" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Interlink --version 1.5.0
                    
#r "nuget: Interlink, 1.5.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Interlink@1.5.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Interlink&version=1.5.0
                    
Install as a Cake Addin
#tool nuget:?package=Interlink&version=1.5.0
                    
Install as a Cake Tool

Static Badge NuGet Version NuGet Downloads

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.


โœจ 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
  • ๐Ÿ”„ Pre and Post Processors for enhanced lifecycle control
  • ๐Ÿ” Assembly scanning for automatic handler registration
  • ๐Ÿงช Custom service factory injection
  • ๐Ÿ”„ Pipeline ordering via attributes or configuration
  • ๐Ÿšจ Dedicated HandlerNotFoundException
  • โœ… Compatible with .NET Standard 2.0+ to .NET 10
  • ๐Ÿ“ฆ Optional packages: Logging, FluentValidation, ASP.NET Core, Analyzer

๐Ÿ“ฆ Installation

dotnet add package Interlink

Optional packages:

dotnet add package Interlink.Extensions.Logging
dotnet add package Interlink.Extensions.Validation
dotnet add package Interlink.AspNetCore
dotnet add package Interlink.Analyzers

โš™๏ธ Setup

Register Interlink in Program.cs (or Startup.cs):

builder.Services.AddInterlink();

Scan a specific assembly:

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

Configure pipeline behaviors and optional custom factory:

builder.Services.AddInterlink(options =>
{
    // Open-generic behaviors (order is optional; lower runs first / outermost)
    options.AddBehavior(typeof(LoggingBehavior<,>), order: 0);
    options.AddBehavior(typeof(ValidationBehavior<,>), order: 1);

    // Optional custom resolution factory
    options.ServiceFactory = type => /* your custom resolver */;
}, typeof(MyHandler).Assembly);

With the extension packages:

builder.Services.AddInterlink(typeof(MyHandler).Assembly);
builder.Services.AddInterlinkLogging();
builder.Services.AddInterlinkValidation(typeof(MyValidator).Assembly);
builder.Services.AddInterlinkAspNetCore();   // registers exception filter

๐Ÿ“จ Request / Response Pattern

1. Define a request and handler

using Interlink;
using Interlink.Contracts;

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

    public sealed 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. Send the request

[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);
    }
}

If no handler is registered, Send throws HandlerNotFoundException.


๐Ÿ“ฃ Notifications (Publish / Subscribe)

1. Define a notification

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

2. Create one or more handlers

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

public sealed class WriteAuditLog : INotificationHandler<UserCreated>
{
    public Task Handle(UserCreated notification, CancellationToken cancellationToken)
    {
        Console.WriteLine($"Audit: user {notification.UserName} created");
        return Task.CompletedTask;
    }
}

3. Publish

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

๐Ÿงฌ Pipeline Behaviors

Pipeline behaviors wrap the handler and can run logic before and after it.

Signature (correct order)

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

Example behavior

public sealed class TimingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : notnull
{
    public async Task<TResponse> Handle(
        TRequest request,
        RequestHandlerDelegate<TResponse> next,
        CancellationToken cancellationToken)
    {
        var sw = Stopwatch.StartNew();
        var response = await next(cancellationToken);
        sw.Stop();
        Console.WriteLine($"{typeof(TRequest).Name} took {sw.ElapsedMilliseconds} ms");
        return response;
    }
}

Ordering

Use the attribute (lower value runs first / outermost):

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

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

Or supply the order when registering:

builder.Services.AddInterlink(options =>
{
    options.AddBehavior(typeof(FirstBehavior<,>), order: 1);
    options.AddBehavior(typeof(SecondBehavior<,>), order: 2);
});

๐Ÿ”„ Pre and Post Processors

Pre-processors run before the pipeline.
Post-processors run after a successful pipeline.

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

public sealed class MyRequestPostProcessor : IRequestPostProcessor<GetAllPets.Query, List<string>>
{
    public Task Process(GetAllPets.Query request, List<string> response, CancellationToken cancellationToken)
    {
        Console.WriteLine($"[Post] returned {response.Count} pets");
        return Task.CompletedTask;
    }
}

They are discovered automatically by AddInterlink().


๐Ÿ“‹ Built-in Logging Behavior

dotnet add package Interlink.Extensions.Logging
builder.Services.AddInterlinkLogging();

This registers LoggingBehavior<TRequest, TResponse>, which logs:

  • request start
  • successful completion + elapsed milliseconds
  • exceptions

โœ… FluentValidation Integration

dotnet add package Interlink.Extensions.Validation
// Registers ValidationBehavior + scans for IValidator<T>
builder.Services.AddInterlinkValidation(typeof(CreateUserValidator).Assembly);

Example validator:

public sealed class CreateUserValidator : AbstractValidator<CreateUser.Command>
{
    public CreateUserValidator()
    {
        RuleFor(x => x.Email).NotEmpty().EmailAddress();
        RuleFor(x => x.Name).NotEmpty().MaximumLength(100);
    }
}

When validation fails, a FluentValidation.ValidationException is thrown (mapped to 400 by the ASP.NET Core filter if you use it).


๐ŸŒ ASP.NET Core Integration

dotnet add package Interlink.AspNetCore
builder.Services.AddControllers();
builder.Services.AddInterlinkAspNetCore();   // adds InterlinkExceptionFilter

The filter maps:

Exception HTTP Status Response
HandlerNotFoundException 404 ProblemDetails
ValidationException* 400 ValidationProblemDetails

* FluentValidation support is optional and detected at runtime (no hard dependency).


๐Ÿ” Analyzer (missing handler detection)

dotnet add package Interlink.Analyzers

Produces diagnostic ILINK001 (warning) when a type implements IRequest<TResponse> but no corresponding IRequestHandler<TRequest, TResponse> is found in the compilation.


๐Ÿ“ฆ API Overview

Core contracts

public interface IRequest<out TResponse> { }

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

public interface INotification { }

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

Sender & Publisher

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

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

Pipeline

public delegate Task<TResponse> RequestHandlerDelegate<TResponse>(CancellationToken cancellationToken = default);

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

Pre / Post processors

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

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

Exception

public class HandlerNotFoundException : InvalidOperationException
{
    public Type RequestType { get; }
    public Type? HandlerType { get; }
}

๐Ÿš€ Roadmap status

Version Status Highlights
1.0 โ€“ 1.3 โœ… Released Core mediator, notifications, pipelines, pre/post, performance
1.4 โœ… Released .NET Standard 2.0+
1.5 โœ… Current Logging, Validation, ASP.NET Core, Analyzer, exceptions, ordering fixes

Future ideas

  • Request cancellation / timeout behaviors
  • Metrics & tracing support
  • Dynamic / externalized pipeline configuration

๐Ÿ“œ License

MIT License ยฉ ManuHub

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on Interlink:

Package Downloads
Interlink.AspNetCore

ASP.NET Core integration for the Interlink mediator library (filters, exception handling, helpers).

Interlink.Extensions.Logging

Built-in logging pipeline behavior for the Interlink mediator library.

Interlink.Extensions.Validation

FluentValidation integration for the Interlink mediator library.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.5.1 192 7/31/2026
1.5.0 154 7/31/2026
1.4.2 147 3/24/2026
1.4.0 241 11/24/2025
1.3.1 247 7/10/2025
1.3.0 246 5/4/2025
1.2.1 219 5/2/2025
1.2.0 176 4/26/2025
1.1.0 181 4/19/2025
1.0.1 323 4/15/2025
1.0.0 284 4/15/2025