PowerPipe 1.1.0-rc

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

// Install PowerPipe as a Cake Tool
#tool nuget:?package=PowerPipe&version=1.1.0-rc&prerelease

PowerPipe: A .NET Library for Constructing Advanced Pipelines with Fluent Interface

GitHub Workflow Status (with event) Nuget Nuget

PowerPipe is a versatile .NET library designed to streamline the process of building advanced pipelines using a fluent interface. The primary objective of this project is to eliminate the need for writing boilerplate code when implementing pipelines.

Table of Contents

Features and Benefits

  • Developed using .NET 6 for optimal performance and compatibility.
  • Offers a readable and intuitive API that simplifies pipeline construction.

Installation

You can easily integrate PowerPipe into your project by installing the required NuGet packages. Use the following commands in the Package Manager Console or .NET CLI:

Package Manager Console

Install-Package PowerPipe
Install-Package PowerPipe.Extensions.MicrosoftDependencyInjection

.NET CLI

dotnet add package PowerPipe
dotnet add package PowerPipe.Extensions.MicrosoftDependencyInjection

Core Components

PipelineContext: Abstract Context Class

PipelineContext serves as the foundational abstract context class from which all specific contexts should inherit. It provides a generic representation that encapsulates the outcome of the pipeline.

public abstract class PipelineContext<TResult>
    where TResult : class
{
    public abstract TResult GetPipelineResult();
}

Pipeline: Constructing Pipelines

The Pipeline class represents a generic pipeline implementation. It is responsible for connecting all pipeline steps internally and executing the initial step to kickstart the process.

public class Pipeline<TContext, TResult> : IPipeline<TResult>
    where TContext : PipelineContext<TResult>
    where TResult : class
{
    // Implementation details...
}
Pipeline Methods
RunAsync
public async Task<TResult> RunAsync(CancellationToken cancellationToken, bool returnResult = true)

The RunAsync method is the primary entry point for executing the pipeline. It allows you to specify whether you need the result of the pipeline or not. For nested pipelines, the returnResult parameter should be set to false.

Pipeline Steps: Building Blocks of Pipelines

IPipelineStep Interface

The IPipelineStep interface defines the blueprint for creating custom pipeline steps. You should implement this interface to describe your own pipeline steps.

public interface IPipelineStep<TContext>
{
    IPipelineStep<TContext> NextStep { get; set; }
    Task ExecuteAsync(TContext context, CancellationToken cancellationToken);
}
IPipelineParallelStep Interface

The IPipelineParallelStep interface defines the blueprint for creating custom parallel pipeline steps.

public interface IPipelineParallelStep<TContext>
{
    Task ExecuteAsync(TContext context, CancellationToken cancellationToken);
}
ExecuteAsync Method

The ExecuteAsync method is the core logic execution point for a pipeline step.

IPipelineCompensationStep Interface

The IPipelineParallelStep interface defines the blueprint for creating custom compensation steps.

public interface IPipelineCompensationStep<TContext>
{
    Task CompensateAsync(TContext context, CancellationToken cancellationToken);
}
Pre-implemented Steps

Several steps are implemented and executed internally, contributing to the pipeline flow. While they are abstracted away, it's beneficial to be aware of them.

  • InternalStep: An abstract class that is base for all internal steps.

  • LazyStep: A step that acts as a 'decorator' for other steps, ensuring thread safety.

  • AddIfStep: Adds a step to the main pipeline based on a specified predicate.

  • AddIfElseStep: Adds a step to the pipeline conditionally, branching based on a predicate.

  • IfPipelineStep: Adds a nested pipeline based on a predicate.

  • CompensationStep: Adds compensation step and handles compensation of parent steps.

  • ParallelStep: Adds step that handles parallel step execution.

  • FinishStep: Automatically added as the final step of the pipeline.

PipelineStepFactory: Step Factory for Dependency Injection

The PipelineStepFactory class implements the IPipelineStepFactory interface, responsible for obtaining steps from Dependency Injection (DI).

public class PipelineStepFactory : IPipelineStepFactory
{
    // Implementation details...
}

PipelineBuilder: Building Pipelines

The PipelineBuilder class is the primary tool for constructing pipelines. It allows you to define the sequence of steps and their conditions.

public sealed class PipelineBuilder<TContext, TResult>
    where TContext : PipelineContext<TResult>
    where TResult : class
{
    // Implementation details...
}
PipelineBuilder Methods
Add
public PipelineBuilder<TContext, TResult> Add<T>()
    where T : IPipelineStep<TContext>

The Add method appends a step to the end of the pipeline.

AddIf
public PipelineBuilder<TContext, TResult> AddIf<T>(Predicate<TContext> predicate)
    where T : IPipelineStep<TContext>

The AddIf method adds a step to the pipeline based on a specified predicate.

If
public PipelineBuilder<TContext, TResult> If(Func<bool> predicate, Func<PipelineBuilder<TContext, TResult>, PipelineBuilder<TContext, TResult>> action)

The If method adds a nested pipeline based on a predicate.

If (with context)
public PipelineBuilder<TContext, TResult> If(Func<TContext, bool> predicate, Func<PipelineBuilder<TContext, TResult>, PipelineBuilder<TContext, TResult>> action)

Similar to the previous method, the If method adds a nested pipeline, but this time it accepts a predicate with access to the TContext object.

OnError
public PipelineBuilder<TContext, TResult> OnError(PipelineStepErrorHandling errorHandling, TimeSpan? retryInterval = null, int? maxRetryCount = null, Predicate<TContext> predicate = null)

The OnError method adds error-handling behavior to the step. Currently available error handling behaviors: Suppress - suppress error and proceed to next step; Retry - retry step execution.

Optional parameters: retryInterval - interval between retries; default value - 1 second. maxRetryCount - retries count; default value - 1. predicate - context-based predicate that indicates whether error handling should apply or not.

CompensateWith
public PipelineBuilder<TContext, TResult> CompensateWith<T>()

The CompensateWith method adds compensation step to the previous added step in pipeline.

Note! That CompensationWith method can be applied to the internal pipeline step as well for the whole internal pipeline

Parallel
public PipelineBuilder<TContext, TResult> Parallel(Func<PipelineBuilder<TContext, TResult>, PipelineBuilder<TContext, TResult>> action, int maxDegreeOfParallelism = -1)

The Parallel method adds a nested pipeline that is responsible for adding steps for parallel execution.

Build
public IPipeline<TResult> Build()

The Build method finalizes the pipeline construction by adding a FinishStep<TContext> and returning the built pipeline as an IPipeline<TResult> object.

Extensions: Microsoft Dependency Injection

The PowerPipe.Extensions.MicrosoftDependencyInjection extension provides integration with Microsoft Dependency Injection.

Methods
AddPowerPipe
public static IServiceCollection AddPowerPipe(this IServiceCollection serviceCollection)

The AddPowerPipe method adds the IPipelineStepFactory to the Dependency Injection container.

AddPowerPipeStep
public static IServiceCollection AddPowerPipeStep<TStep, TContext>(this IServiceCollection serviceCollection, ServiceLifetime lifetime = ServiceLifetime.Transient)
    where TStep : class, IPipelineStep<TContext>
    where TContext : PipelineContext<Type>

The AddPowerPipeStep method adds your custom pipeline steps to the Dependency Injection container with a transient scope by default.

AddPowerPipeCompensationStep
public static IServiceCollection AddPowerPipeCompensationStep<TStep, TContext>(this IServiceCollection serviceCollection, ServiceLifetime lifetime = ServiceLifetime.Transient)
    where TStep : class, IPipelineCompensationStep<TContext>
    where TContext : class

The AddPowerPipeStep method adds your custom pipeline steps to the Dependency Injection container with a transient scope by default.

Examples

Example: Processing Customer Orders

Suppose you're working on an e-commerce platform, and you need to process incoming customer orders. Each order involves several steps, such as validation, pricing calculation, and inventory management. Let's see how PowerPipe can help you build a pipeline to handle this process.

Step 1: Define the Pipeline Context

First, let's create a pipeline context that will hold the information related to the order processing. We'll define a simple context class that contains order details:

public class OrderContext : PipelineContext<OrderResult>
{
    // Properties and methods specific to the context
}

Step 2: Implement Pipeline Steps

Next, we'll create individual steps for our pipeline. For simplicity, let's focus on two steps: validation and pricing calculation. We'll implement these steps by implementing the IPipelineStep<OrderContext> interface:

public class ValidationStep : IPipelineStep<OrderContext>
{
    public IPipelineStep<OrderContext> NextStep { get; set; }

    public async Task ExecuteAsync(OrderContext context, CancellationToken cancellationToken)
    {
        // Validate the order and update the context
        // Implement your validation logic here
    }
}

public class PricingStep : IPipelineStep<OrderContext>
{
    public IPipelineStep<OrderContext> NextStep { get; set; }

    public async Task ExecuteAsync(OrderContext context, CancellationToken cancellationToken)
    {
        // Calculate pricing for the order and update the context
        // Implement your pricing logic here
    }
}

Step 3: Build the Pipeline

Now, let's use PowerPipe to build our pipeline. We'll create a pipeline builder and add our steps to it based on certain conditions:

var pipeline = new PipelineBuilder<OrderContext, OrderResult>()
    .Add<ValidationStep>()
    .AddIf<PricingStep>(context => context.IsValid)
    .Build();

In this example, the AddIf method adds the PricingStep only if the order is valid.

Step 4: Execute the Pipeline

Finally, we'll execute the pipeline using the RunAsync method:

var orderContext = new OrderContext();
var orderResult = await pipeline.RunAsync(orderContext, CancellationToken cancellationToken);

Conclusion

In this example, we've explored how to use the PowerPipe library to build advanced pipelines in a .NET application. By following the steps outlined in the example, you can effectively manage complex data processing tasks with ease. PowerPipe's fluent interface and integration with Microsoft Dependency Injection make it a powerful tool for creating maintainable and reusable pipelines.

By incorporating PowerPipe into your development workflow, you can enhance the efficiency and readability of your code while tackling intricate data processing challenges. As you continue to explore the library and its features, you'll discover even more ways to leverage its capabilities in your projects.

Contributors are Welcome!

If you have any questions or suggestions, feel free to contact me at m.vorchakov97@gmail.com. I'm welcome contributions from the community to enhance and improve the PowerPipe library. Your input is highly valued!

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

    • No dependencies.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on PowerPipe:

Package Downloads
PowerPipe.Extensions.MicrosoftDependencyInjection

A library for .NET that uses a fluent interface to construct advanced workflows with ease

PowerPipe.Visualization

A library for .NET that uses a fluent interface to construct advanced workflows with ease

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.0.0 228 3/22/2024
2.0.0-rc2 281 2/9/2024
2.0.0-rc1 84 2/8/2024
1.2.0 6,857 11/13/2023
1.2.0-rc5 117 11/10/2023
1.2.0-rc4 124 11/9/2023
1.2.0-rc3 119 11/7/2023
1.2.0-rc2 105 11/7/2023
1.2.0-rc 104 11/7/2023
1.1.2 351 9/21/2023
1.1.2-beta 229 9/21/2023
1.1.1 165 9/12/2023
1.1.0 166 9/11/2023
1.1.0-rc 155 9/6/2023
1.0.3 5,136 7/17/2023
1.0.2 11,248 2/8/2023
1.0.1 636 1/16/2023
1.0.0 392 1/3/2023
1.0.0-beta 179 1/3/2023
0.1.10 4,940 5/10/2022
0.1.9 519 5/10/2022
0.1.8 535 5/6/2022
0.1.7 534 5/5/2022
0.1.6 543 4/21/2022
0.1.5 519 4/21/2022
0.1.4 545 4/21/2022
0.1.3 548 4/18/2022
0.1.2 559 2/14/2022
0.1.1 518 2/14/2022
0.1.0 569 2/14/2022