MSL.Plumber.Pipeline 1.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package MSL.Plumber.Pipeline --version 1.1.0                
NuGet\Install-Package MSL.Plumber.Pipeline -Version 1.1.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="MSL.Plumber.Pipeline" Version="1.1.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add MSL.Plumber.Pipeline --version 1.1.0                
#r "nuget: MSL.Plumber.Pipeline, 1.1.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.
// Install MSL.Plumber.Pipeline as a Cake Addin
#addin nuget:?package=MSL.Plumber.Pipeline&version=1.1.0

// Install MSL.Plumber.Pipeline as a Cake Tool
#tool nuget:?package=MSL.Plumber.Pipeline&version=1.1.0                

Build Status

.NET Tests .NET Publish Nuget Nuget Nuget Nuget

<div> <img src="https://github.com/marklauter/plumber/blob/main/images/plumber.svg" title="plumber-logo" alt="plumber-logo" height="128" />

Plumber

Pipelines for host-free projects like AWS Lambda, Console, etc.

Plumber is a request pipeline that supports middleware delegates and classes. It provides configuration, dependency injection, and middleware pipeline services. It's useful for AWS Lambdas, Azure Functions, queue event handlers, and similar use cases.

References

Plumber is based on this article: How is the ASP.NET Core Middleware Pipeline Built - Steve Gorden, July 2020

Getting Started

If you're not familiar with middleware pipelines, Microsoft has a good primer on how middleware works in ASP.NET Core.

Installing

To install, use the following command: dotnet add package MSL.Plumber.Pipeline

Usage

  1. Create an IRequestHandlerBuilder<TRequest, TResponse> by calling one of the static RequestHandlerBuilder.New methods.
  2. The request handler builder adds default configuration providers for appsettings files, environment variables, command line args, and user secrets.
  3. Handle additional configuration scenarios through the IConfigurationManager Configuration property on the builder.
  4. Register services with the IServiceCollection Services property.
  5. Use the Build method to create an IRequestRequestDelegate<TRequest, TResponse> instance.
  6. Configure the request delegate pipeline by calling the Use methods on the request handler.
  7. Call the Prepare method on the request handler to compile the pipeline. If you don't call Prepare, the pipeline will be compiled when the first request is processed.
  8. Call the InvokeAsync method on the request handler to forward the request to the pipeline.
  9. Within your middleware delegates, or IMiddleware implementations, always invoke Next to pass the request context to the next delegate in the pipeline.
  10. Always call context.CancelationToken.ThrowIfCancellationRequested() to check for cancellation requests before processing the request or invoking Next.
  11. To terminate or "short circuit" the pipeline don't invoke Next.
  12. Set the response value in the request context to return a value from the pipeline execution.

Sample AWS Lambda Projects

Examples

The following examples demonstrate common usage scenarios.

Simplest Example - no config, no services, no middleware

In this sample, we create a request handler that does nothing with no configuration, no service registration, and no user-defined middleware. This is the simplest possible example.

var request = "Hello, World!";

var handler = RequestHandlerBuilder
    .New<string, string>()
    .Build();

var response = await handler.InvokeAsync(request);

Assert.True(String.IsNullOrEmpty(response));

Middleware Delegate Example

In this sample, we create a request handler with user-defined middleware that converts the request to uppercase.

var request = "Hello, World!";

var handler = RequestHandlerBuilder.New<string, string>()
    .Build()
    .Use(async (context, next) =>
    {
        context.CancelationToken.ThrowIfCancellationRequested();
        context.Response = context.Request.ToUpperInvariant();
        await next(context); // call next to pass the request context to the next delegate in the pipeline
    })
    .Prepare();

var response = await handler.InvokeAsync(request);

Assert.Equal(request.ToUpperInvariant(), response);

Middleware Class Example

In this sample, we create a request handler with a user-defined IMiddleware implementation that converts the request to lowercase.

First, we define the middleware class, which receives the next middleware delegate in the pipeline in its constructor. The middleware is responsible for invoking the next delegate. You will short-circuit the pipeline if you don't invoke the next delegate. An example short-circuit scenario might be a request validation middleware that returns an error response if the request is invalid. The middleware is also responsible for short-circuiting when the pipeline is explicitly canceled via the context.CancelationToken.

Constructor-based dependency injection is supported for IMiddleware implementations, with the condition that the next delegate must be the first argument in the constructor.

internal sealed class ToLowerMiddleware(RequestMiddleware<string, string> next)
    : IMiddleware<string, string>
{
    private readonly RequestMiddleware<string, string> next = next
        ?? throw new ArgumentNullException(nameof(next));

    public Task InvokeAsync(Context<string, string> context)
    {
        context.CancelationToken.ThrowIfCancellationRequested();
        context.Response = context.Request.ToLowerInvariant();
        return next(context); // call next to pass the request context to the next delegate in the pipeline
    }
}

Next, we register the middleware with the request handler with the Use<T> method.

var request = "Hello, World!";

var handler = RequestHandlerBuilder.New<string, string>()
    .Build()
    .Use<ToLowerMiddleware>()
    .Prepare();

var response = await handler.InvokeAsync(request);

Assert.Equal(request.ToLowerInvariant(), response);

Builder Configuration Example

Use the IRequestHandlerBuilder.Configuration property to add configuration providers, like AddInMemory or AddJsonFile.

var builder = RequestHandlerBuilder.New<string, string>(args);

builder.Configuration
    .AddInMemoryCollection(new Dictionary<string, string> { { "MyKey", "MyValue" } });

var handler = builder.Build();

Builder Service Registration Example

Use the IRequestHandlerBuilder.Services property to register services.

var builder = RequestHandlerBuilder.New<string, string>(args);

builder.Services
    .AddSingleton<IMyService, MyService>()
    .AddSerilog();

var handler = builder.Build();

Void Response Example

The Void type is for request handlers that don't return a response.

public readonly struct Void { }

Use it as the response type for request handlers that don't return a response.

var handler = RequestHandlerBuilder.New<string, Void>() // Void TResponse type
    .Build()
    .Prepare();

<div>

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  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 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on MSL.Plumber.Pipeline:

Package Downloads
MSL.Plumber.Serilog.Extensions

Plumber.Serilog.Extensions provides Serilog middleware extensions for the Plumber pipeline libary.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.3.0 73 7/26/2024
2.2.0 144 7/22/2024
2.1.0 97 7/3/2024
2.0.2 122 6/26/2024
2.0.1 124 6/26/2024
2.0.0 77 6/25/2024
1.1.1 111 6/22/2024
1.1.0 107 6/22/2024
1.0.50 118 6/22/2024
1.0.49 147 5/16/2024
1.0.48 130 5/10/2024
1.0.47 206 5/7/2024
1.0.46 114 5/6/2024
1.0.45 116 5/4/2024
1.0.42 111 5/4/2024
1.0.40 126 5/4/2024
1.0.38 126 5/4/2024
1.0.37 106 5/4/2024
1.0.36 108 5/4/2024
1.0.35 115 5/4/2024