PipeR
WMB Online
WMB Online
industrial

PipeR

A Lightweight, High-Performance Request Pipeline for .NET.

Internal Designation: PipeR Core

active
v0.0.4-ci
actively maintained
Open Source
Last updated: 12/5/2025

Developed in response to the commercialization of MediatR, PipeR provides a clean, minimal, and high-performance mediator-style pipeline. It supports composable behaviors, ASP.NET Core integration, and clean architectural boundaries. The project reflects a philosophy of reducing dependency weight while maintaining architectural elegance.

Project Milestones

8/13/2025

Project Inception

Initiated as an open-source alternative to MediatR following its transition to a commercial license model.

9/1/2025

Core Pipeline Architecture Stabilized

Implemented lightweight request/response pipeline with middleware-like extensibility.

10/18/2025

ASP.NET Core Integration

Released PipeR.Extensions.AspNetCore for seamless DI and HTTP pipeline integration.

12/5/2025

CI Pre-Release v0.0.4

Published CI builds to NuGet with structured package separation.

Project Strategy

Key Decisions

  • Designed as a lightweight alternative to MediatR after its licensing change.
  • Avoided unnecessary abstractions to reduce performance overhead.
  • Separated core pipeline logic from ASP.NET Core integration.
  • Maintained minimal dependencies to reduce package bloat.

Challenges Solved

  • Ensured composable middleware-like behavior without heavy reflection.
  • Balanced extensibility with simplicity.
  • Maintained compatibility with existing mediator-driven architectures.

Future Plans

  • Stabilize v1.0 public release.
  • Expand extension packages (logging, validation, resilience).
  • Introduce benchmarking comparisons against MediatR.
  • Improve documentation and example repositories.

Project detail

The following detail mirrors the full wiki project write-up.

PipeR is a purpose-built middleware-style pipeline library for .NET applications, designed to streamline request/response handling within clean architectures. Inspired by the Mediator pattern (Γ  la MediatR) but built with clarity, performance, and modularity in mind, PipeR empowers developers to structure business logic as a series of composable steps.

πŸ” Why Create PipeR?

PipeR was born from a combination of architectural need, performance considerations, and a shift in the open-source ecosystem surrounding .NET.

Like many .NET developers, I relied heavily on MediatR for years as the go-to library for decoupling request handling. However, the announcement by its creator Jimmy Bogard that MediatR would be transitioning to a commercial license model sparked reflection β€” not just about licensing, but about control, transparency, and long-term project autonomy.

This commercialization trend, also affecting libraries like AutoMapper, is well covered by Milan Jovanovic in his thoughtful commentary: β€œOpen Source in .NET is Changing”.

At the same time, inspiration struck from the community. A video by Mohamad Dbouk titled β€œBuild Your Own Mediator in .NET” laid out a minimalist but clear implementation of the Mediator pattern. This helped crystallize my thinking: I didn’t need to fork MediatR or wait for community reactions β€” I could build my own approach, one tailored to the specific patterns and performance characteristics I value in my production services.

Thus, PipeR was envisioned β€” not as a clone, but as a composable, high-performance middleware engine that emphasizes:

  • βœ… Explicit flow control through fluent configuration
  • βœ… Strong typing for both requests and middleware
  • βœ… Lightweight footprint with zero reflection at runtime
  • βœ… Plug-and-play middleware and validation support
  • βœ… Production resilience without third-party dependency entanglement

PipeR was born out of the desire for a more controlled, pluggable, and high-performance solution β€” tailored for backends where performance and traceability matter.

🧱 Core Concepts

  • Request Types – Define the request + response types (e.g., LoginUserRequest : IRequest<LoginResponse>)
  • Handlers – Pure handlers containing business logic
  • Middleware – Pre/post-processing components injected into the pipeline (e.g., logging, metrics, validation)
  • PipelineBuilder – Fluent API to register steps and compose the request execution flow

πŸ“¦ Basic Usage - PipelineBuilder

var pipeline = new PipelineBuilder()
    .Use<LoggingMiddleware>()
    .Use<AuthorizationMiddleware>()
    .UseHandler<LoginRequestHandler>()
    .Build();

var result = await pipeline.ExecuteAsync(new LoginUserRequest { ... });

Each middleware gets a chance to inspect, short-circuit, or transform the request/response. Everything is strongly typed, and you remain in full control of registration order and dependency resolution.

πŸ“š Request/Response Separation (CQRS-Light)

While PipeR focuses heavily on composable middleware pipelines, it also promotes a clean and consistent request/response structure. Inspired by the CQRS pattern, this approach brings clarity and separation of concerns without the complexity of full-blown CQRS implementations.

Here's how simple a controller becomes:

[HttpGet]
public async Task<ActionResult<GetAllBooksResponse>>
    GetBooks([FromQuery] GetAllBooksQuery query) =>
    await this.HandleRequest(query);

And with the help of a base controller abstraction, you inject your IPiper dependency once and unify request routing:

public class BookControllerBase : ControllerBase
{
    protected readonly IPiper _piper;

    public BookControllerBase(IPiper piper)
    {
        _piper = piper;
    }

    protected async Task<ActionResult> HandleRequest<TResponse>(IRequest<TResponse> request)
    {
        var userIdClaim = User.FindFirst("UserId");
        if (userIdClaim != null && request is BaseRequest baseRequest)
        {
            baseRequest.UserId = Guid.Parse(userIdClaim.Value);
            return Ok(await _piper.Send(request));
        }

        return Forbid();
    }
}

πŸ“ Requests and Responses

public class GetAllBooksRequest : BaseRequest
{
    public int PageNumber { get; set; } = 1;
    public int PageSize { get; set; } = 20;
    public string? SearchTerm { get; set; }
}

public class GetAllBooksResponse : BaseResponse
{
    public PagedResult<BookDto> Books { get; set; } = new();
}

πŸ”€ Query + Validation Layer

public class GetAllBooksQuery : GetAllBooksRequest, IRequest<GetAllBooksResponse> {}

public class GetAllBooksValidator : AbstractValidator<GetAllBooksQuery>
{
    public GetAllBooksValidator()
    {
        RuleFor(x => x.ApiKey)
            .NotEmpty().WithMessage("A valid API Key must be provided!");
        RuleFor(x => x.UserId)
            .NotNull().WithMessage("User Id must be supplied!");
    }
}

βš™οΈ Abstract Request Handler

Your handlers can inherit from a base class that encapsulates common patterns, enforcing consistency and reducing duplication:

public abstract class RequestHandlerBase<TRequest, TResponse, TValidator> 
    : IRequestHandler<TRequest, TResponse>
    where TRequest : BaseRequest, IRequest<TResponse>
    where TResponse : BaseResponse, new()
    where TValidator : AbstractValidator<TRequest>, new()
{
    // Abstract Handle logic with optional validation
}

This architecture ensures that all requests are routed, validated, and handled consistently β€” reducing boilerplate and centralizing behavior for cross-cutting concerns.

πŸ“Š Advantages Over MediatR

  • πŸš€ No reflection or dynamic resolution overhead
  • 🧩 Middleware chaining using pure DI or fluent configuration
  • πŸ’¬ Transparent request flow, easier debugging
  • πŸ›‘οΈ Cleaner separation of concerns in complex apps

πŸ’‘ When to Use PipeR

PipeR excels in systems that:

  • Need structured pipelines (like CQRS or request-response)
  • Emphasize testability, modularity, and observability
  • Run in high-performance or resource-constrained environments (e.g., containers, microservices)
  • Desire a MediatR alternative without the baggage

πŸ§ͺ Example Scenario: Validating and Handling a Login

// Middleware
public class ValidationMiddleware<TRequest, TResponse> : IPipelineMiddleware<TRequest, TResponse>
{
    public async Task<TResponse> InvokeAsync(
        TRequest request, 
        Func<TRequest, Task<TResponse>> next)
    {
        Validate(request); // throw on failure
        return await next(request);
    }
}

// Handler
public class LoginHandler : IRequestHandler<LoginRequest, LoginResponse>
{
    public async Task<LoginResponse> Handle(LoginRequest request)
    {
        return new LoginResponse { Token = "abc123" };
    }
}

🌐 GitHub

The PipeR project will soon be available on GitHub, alongside full documentation and integration examples.

πŸ“¦ NuGet Plans

The library will be packaged into two NuGet packages:

  • PipeR.Core – Core pipeline interfaces and engine
  • PipeR.AspNetCore – an extension on top of Core for use in ASP.NET Core projects

πŸ“š Coming Soon

  • πŸ”Œ MediatR compatibility bridge
  • 🎯 Benchmark comparisons
  • πŸ“ˆ OpenTelemetry middleware
  • πŸ§ͺ Unit testing harnesses for pipelines and middleware

PipeR is your fast track to clean, composable, middleware-first request handling in .NET.

Filed under: .NET, CQRS, Middleware, Clean Architecture, Performance, MediatR Alternative