IO.Pipeline 1.0.1

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

// Install IO.Pipeline as a Cake Tool
#tool nuget:?package=IO.Pipeline&version=1.0.1

Pipeline

Represents an implementation of Pipeline pattern for .NET. It allows to break down a large bunch of code into small pieces for better readability, extensibility and testability.

Usage

First of all you should create a type which will be passed between the pipeline steps:

pubclic class InsurancePremiumModel
{
  public decimal TotalPremium { get; set; }
}

Use PipelineBuilder to create pipeline and fill one with steps. As an example lets assume that we want to calculate common insurance premium for set of customers:

var customers = GetCustomers();
var customersCount = customers.Count();

var builder = PipelineBuilder<InsurancePremiumModel>
  .StartWith((model, next) => {
    var basePrice = GetBasePrice(Options.Ambulance, customers);
    var ambulancePremium = _ambulanceService.Calculate(basePrice);
    model.TotalPremium += customersCount * ambulancePremium;
    return next.Invoke(model);
  })
  .AddStep((model, next) => {
    var basePrice = GetBasePrice(Options.Dental, customers);
    var ambulancePremium = _dentalService.Calculate(basePrice);
    model.TotalPremium += customersCount * ambulancePremium;
    return next.Invoke(model);
  })
  .AddStep((model, next) => {
    var basePrice = GetBasePrice(Options.HomeCare, customers);
    var homeCarePremium = _homeCareService.Calculate(basePrice);
    model.TotalPremium += customersCount * homeCarePremium;
    return next.Invoke(model);
  });

It is possible to describe a pipeline step as a type by implementing an interface IPipelineStep<T>. In an example below we create RoundOffStep to round off total insurance premium we got:

public class RoundOffStep
  : IPipelineStep<PriceModel>
  {
        public Task<PriceModel> InvokeAsync(PriceModel input, Func<PriceModel, Task<PriceModel>> next)
        {
            input.TotalPremium = RoundOff(input.TotalPremium);
            return next.Invoke(input);
        }
        
        private decimal RoundOff(decimal price)
        {
            var rem = price % 10;
            
            if (rem == 0) return price;
            
            var result = Math.Round(price / 10, MidpointRounding.AwayFromZero) * 10;

            return rem < 5 ? result + 10.00m : result;
        }

    }

So, you can add newly created step to builder like this:

  builder.AddStep<RoundOffStep>();

To obtain pipeline object use method Build of PipelineBuilder. After that you can call method ExecuteAsync of pipeline to perform all added steps:

  var pipeline = builder.Build();
  var result = await pipeline.ExecuteAsync(new InsurancePremiumModel());

Usage with .NET Core

You can register all classes which implement IPipelineStep interface within ConfigureServices method of Startup class.

  services.RegisterSteps();

The step classes can contain parametric constructor. After that it is possible to inject objects of steps into controllers, services and build pipeline with them:

    public class Step1
        : IPipelineStep<string>
    {
        private readonly ISomeService _someService;

        public Step1(ISomeService someService)
        {
            _someService = someService;
        }
        public async Task<string> InvokeAsync(string input, Func<string, Task<string>> next)
        {
            input += "STEP1 :" + _someService.GetSomeString(100);
            return await next(input);
        }
    }
    
    public class Step2
        : IPipelineStep<string>
    {
        private readonly ISomeService _someService;

        public Step2(ISomeService someService)
        {
            _someService = someService;
        }
        public async Task<string> InvokeAsync(string input, Func<string, Task<string>> next)
        {
            input += "STEP2 :" + _someService.GetSomeString(100);
            return await next(input);
        }
    }

   public class PipelineController
        : Controller
    {
        private readonly Step1 _step1;
        private readonly Step2 _step2;


        public PipelineController(
            Step1 step1,
            Step2 step2)
        {
            _step1 = step1;
            _step2 = step2;
        }
        
        
        [HttpGet]
        public async Task<ActionResult> ExecutePipelineFromRegisteredSteps()
        {
            var pipeline = PipelineBuilder<string>
                .StartWith(_step1)
                .AddStep(_step2)
                .AddStep(async (data, next) =>
                {
                    data += "Final Step!!!";
                    return await next.Invoke(data);
                })
                .Build();
            
            var result = pipeline.ExecuteAsync("hello, darkness, my old friend \r\n");
                
            return Json(result);
        }
    }

You should register SomeService within ConfigureServices method of Startup class something like this:

  services.AddSingleton<ISomeService, SomeService>();

There is also an extension method RegisterPipeline<T> which lets you simply create and register as singletone an object of Pipeline:

  services.RegisterPipeline<string>(
                builder =>
                    builder
                        .RegisterStep<Step1>()
                        .RegisterStep<Step2>()
            );

After that you can inject object of pipeline into service:

  private readonly IPipeline<string, string> _pipeline;
  
  public PipelineController(
            IPipeline<string, string> pipeline)
            {
              _pipeline = pipeline;
            }
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. 
.NET Core netcoreapp2.2 is compatible.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETCoreApp 2.2

    • No dependencies.

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.2 441 9/11/2020
1.0.1 396 8/26/2020
1.0.0 406 8/26/2020