PipelineMedium 1.0.3

dotnet add package PipelineMedium --version 1.0.3
                    
NuGet\Install-Package PipelineMedium -Version 1.0.3
                    
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="PipelineMedium" Version="1.0.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PipelineMedium" Version="1.0.3" />
                    
Directory.Packages.props
<PackageReference Include="PipelineMedium" />
                    
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 PipelineMedium --version 1.0.3
                    
#r "nuget: PipelineMedium, 1.0.3"
                    
#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 PipelineMedium@1.0.3
                    
#: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=PipelineMedium&version=1.0.3
                    
Install as a Cake Addin
#tool nuget:?package=PipelineMedium&version=1.0.3
                    
Install as a Cake Tool

PipelineMedium is set of classes and interfaces that provides a flexible and extensible solution of middleware pipeline pattern.

Installing

You can install it with NuGet:

dotnet add package PipelineMedium

Concepts

Middleware

Middleware is piece of software that's assembled into a pipeline to handle data and produce result. Each component can choose whether to run the next component in the pipeline and perform work before and after the next component.

//example of middleware function
(request, next) =>
{
    //run before next middleware 
    next(); //invoke next middleware in pipeline
    //run after next middleware 

    //or

    return; //break execution of middleware pipeline (short-circuiting)
}

Middleware components can be of two types: consumable that can only read or modify a request and producible that also returns a result. An individual middleware component can be specified in-line as an anonymous method or it can be defined in a reusable class. Middleware class supports dependency injection via constructor. Default lifetime of middleware class instance is transient, to change lifetime register a middleware in services collection on your own.

//producible middleware class
public class Middleware(IDependency dependency) : IMiddleware<Request, Result>
{
    public Result Invoke(Request request, NextMiddlewareDelegate<Result> next)
    {
        //code
    }
}

//producible async middleware class
public class AsyncMiddleware(IDependency dependency) : IAsyncMiddleware<Request, Result>
{
    public async Task<Result> InvokeAsync(Request request, NextAsyncMiddlewareDelegate<Result> next)
    {
        //code
    }
}

//consumable middleware class
public class Middleware(IDependency dependency) : IMiddleware<Request>
{
    public void Invoke(Request request, NextMiddlewareDelegate next)
    {
        //code
    }
}

//consumable async middleware class
public class AsyncMiddleware(IDependency dependency) : IAsyncMiddleware<Request>
{
    public async Task InvokeAsync(Request request, NextAsyncMiddlewareDelegate next)
    {
        //code
    }
}

//in-line middleware functions
services.AddMedium<Request>()
    .Use((request, next) => { /* code */ })
    .Use((serviceProvider, request, next) => { /* code */ }) //with IServiceProvider
    .Use<Dependency>((dependency, request, next) => { /* code */ }); //with Dependency provided

services.AddMedium<Request, Result>()
    .Use((request, next) => { /* code */ })
    .Use((serviceProvider, request, next) => { /* code */ }) //with IServiceProvider
    .Use<Dependency>((dependency, request, next) => { /* code */ }); //with Dependency provided

Medium

Medium is definition of middleware pipeline. It encapsulates functionality of building, managing a pipeline and provides convenient interface to execute the pipeline.

To define a medium add it to IserviceCollection and configure its middleware pipeline

//add default consumable Medium
services.AddMedium<Request>()
    .Use<Middleware>()
    .Use<NextMiddleware>()
    .UseWhen<ConditionalMiddleware>(r => r.Param == null)
    .Use((request, next) => { /* code */ });

//add default producible Medium 
services.AddMedium<Request, Result>()
    .Use<Middleware>()
    .Use<NextMiddleware>()
    .UseWhen<ConditionalMiddleware>(r => r.Param == null)
    .Use((request, next) => { /* code */ });
    
//you can also add other mediums for the same request, result type by specifying a name (default name is "Default")
//name uniquely identifies a medium for specified request type
services.AddMedium<Request>("DoDifferentWay")
    .Use<OtherMiddleware>()

//name uniquely identifies a medium for specified request and result types combination
services.AddMedium<Request, OtherResult>("DoDifferentWayAndReturnDifferentResult")
    .Use<OtherMiddleware>()

To execute a Medium get an instance from service provider by its generic interface IMedium<TRequest>, IMedium<TRequest, TResult> from service provider. Also IMedium interface available with generic methods for convenient access to different mediums.

var medium = serviceProvider.GetRequiredService<IMedium<Request>>();
await medium.ExecuteAsync(new Request());
await medium.ExecuteAsync("DoDifferentWay", new Request());

var medium = serviceProvider.GetRequiredService<IMedium<Request, Result>>();
var result = await medium.ExecuteAsync(new Request());
var result2 = await medium.ExecuteAsync("DoDifferentWayAndReturnDifferentResult", new Request());

var medium = serviceProvider.GetRequiredService<IMedium>();
await medium.ExecuteAsync<Request>(new Request());
await medium.ExecuteAsync<OtherRequest>(new OtherRequest());

Usage

Define a request type

public class Request {
    public string Param { get; set; }
}

Define a result type if you want medium to return a result

public class Result {
    public string Data { get; set; }
}

Create a middleware to handle the request and to return result if desired. Middleware class must implement middleware interface.

//consumable middleware
public class ConsumeRequestMiddleware(IDependency dependency) : IAsyncMiddleware<Request>
{
    public async Task InvokeAsync(Request request, NextAsyncMiddlewareDelegate next)
    {
        //code
        await next(); //invoke next middleware in pipeline
    }
}

//producible middleware
public class ConsumeRequestAndReturnResultMiddleware(IDependency dependency) : IAsyncMiddleware<Request, Result>
{
    public async Task<Result> InvokeAsync(Request request, NextAsyncMiddlewareDelegate<Result> next)
    {
        //code
        return await next(); //invoke next middleware in pipeline
    }
}

Add medium to IserviceCollection and configure its middleware pipeline.

//add and configure default medium for processing the Request
services.AddMedium<Request>()
    .Use<PrecedingMiddleware>()
    .Use<ConsumeRequestMiddleware>()
    .Use<NextMiddleware>()
    .UseWhen<ConditionalMiddleware>(r => r.Param == null)
    .Use((r, next) => { });

//add and configure default medium for processing the Request and return the Result
services.AddMedium<Request, Result>()
    .Use<PrecedingMiddleware>()
    .Use<ConsumeRequestAndReturnResultMiddleware>()
    .Use<NextMiddleware>()
    .UseWhen<ConditionalMiddleware>(r => r.Param == null)
    .Use((r, next) => { });

Get an instance of medium by its interface using dependency injection

public class SomeController : ControllerBase
{
    public async Task<ActionResult<Result>> Get(Request requestModel, [FromServices] IMedium<Request, Result> medium)
    {
        return await medium.ExecuteAsync(requestModel);
    }

    public async Task<IActionResult> Post(Request requestModel, [FromServices] IMedium<Request> medium)
    {
        await medium.ExecuteAsync(requestModel);

        return Ok();
    }

    public async Task<IActionResult> Put(Request requestModel, [FromServices] IMedium medium)
    {
        await medium.ExecuteAsync<Request>(requestModel);
        await medium.ExecuteAsync<OtherRequest>(new OtherRequest());

        return Ok();
    }
}

Features

Synchronous and asynchronous middleware in one pipeline
services.AddMedium<Request>()
    .Use<SyncMiddleware>()
    .Use<AsyncMiddleware>()
    .Use((r, next) => { })
    .Use(async (r, next, cancellationToken) => { });
Default or termination component of a pipeline. When execution of the pipeline goes next the way down, Medium executes a termination component to end the process and return a result, you can define own behavior of that component.
services.AddMedium<Request>()
    .Use<SomeMiddleware>()
    .Use((r, next) => { next() })
    .UseTermination(r => {
        Console.WriteLine("Execution ended");
    });

services.AddMedium<Request, Result>()
    .Use<SomeMiddleware>()
    .Use((r, next) => { next() })
    .UseTermination(r => {
        return new Result();
    });
Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  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 is compatible.  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 was computed.  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

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.3 136 6/22/2025
1.0.2 225 3/6/2025
1.0.1 219 3/4/2025
1.0.0 368 3/3/2025 1.0.0 is deprecated because it has critical bugs.