SimpleChain 8.0.5

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

// Install SimpleChain as a Cake Tool
#tool nuget:?package=SimpleChain&version=8.0.5

SimpleChain

NuGet version (SimpleChain) GitHub license

A set of extensions to implement in a simple way the Chain-of-responsibility pattern for all types of objects.

Stack used

  • .NET 8
  • xUnit
  • No dependencies

Installation

Depending on your usage, follow one of the guidelines below.

ASP.NET Core

Install with NuGet:

Install-Package SimpleChain

or with .NET CLI:

dotnet add package SimpleChain

How to Use

You can easily create a Chain from every object, Task, IEnumerable or IAsyncEnumerable. All those examples are listened in the project tests:

Consider the example class Sale

internal class Sale
{
    public string? SaleName { get; set; }
    public Product[] Products { get; set; } = Array.Empty<Product>();
    public double Total { get; set; }
    public double Tax { get; set; }
}

internal sealed class Product
{
    public required string Name { get; set; }
    public required double Price { get; set; }
}

You can start a Chain directly like this:

object
var sale = new Sale();

var chain = sale.ToChain()
    .AddNode(sale => 
    {
        sale.SaleName = "Sale1";
        sale.Products = new[] 
        {
            new Product
            {
                Name = "Product1",
                Price = "10"
            },
            new Product
            {
                Name = "Product2",
                Price = "15"
            }
        };
        return sale;
    })
    .AddNode(sale => sale.Products.Sum(x => x.Price));

var total = await chain();

// Total: 25
    
Task
var sale = _repository.GetSale() // returns Task<Sale> type
    .ToChain()
    .AddNode(sale =>
    {
        sale.Total = sale.Products.Sum(x => x.Price);
        return sale;
    })
    .AddNode(sale =>
    {
        sale.Tax = sale.Total * 0.12;
        return sale;
    });
IEnumerable
var sales = new List<Sale>();

var newSales = await sales.ToChain()
    .AddNode(sales =>
    {
        return sales.Select(sale =>
        {
            sale.Total = sale.Products.Sum(x => x.Price);
            return sale;
        });
    })
    .AddNode(sales =>
    {
        return sales.Select(sale =>
        {
            sale.Tax = sale.Total * 0.12;
            return sale;
        });
    });
IAsyncEnumerable
var asyncSales = await _repository.GetSalesAsync() // functions returns IAsyncEnumerable<Sale>
    .ToChain()
    .AddNode(async sales =>
    {
        await foreach(var sale in sales)
        {
            sale.Total = sale.Products.Sum(x => x.Price);
            yield return sale;
        }
    })
    .AddNode(async sales =>
    {
        await foreach(var sale in sales)
        {
            sale.Tax = sale.Total * 0.12;
            yield return sale;
        }
    });

await foreach(var sale in asyncSales.WithCancellationToken(ct))
{
    (...)
}
Or you can use .AddAsyncNode() directly:
var asyncSales = await _repository.GetSalesAsync() // functions returns IAsyncEnumerable<Sale>
    .ToChain()
    .AddAsyncNode(sale =>
    {
        sale.Total = sale.Products.Sum(x => x.Price);
        return sale;
    })
    .AddAsyncNode(sale =>
    {
        sale.Tax = sale.Total * 0.12;
        yield return sale;
    });

await foreach(var sale in asyncSales.WithCancellationToken(ct))
{
    (...)
}

Special Nodes

Chunk Node for IAsyncEnumerable

NOTE: You can specify the total chunk with .Chunk() node

var asyncSales = await _repository.GetSalesAsync() // functions returns IAsyncEnumerable<Sale>
    .ToChain()
    .Chunk(10)
    .AddNode(chunk =>
    {
        return chunk.Select(sale => 
        {
            sale.Total = sale.Products.Sum(x => x.Price);
            return sale;
        });
    })
    .AddNode(chunk =>
    {
        return chunk.Select(sale => 
        {
            sale.Tax = sale.Total * 0.12;
            return sale;
        });
    });

await foreach(var chunk in asyncSales.WithCancellationToken(ct))
{
    (...)
}

Wrapping Node functions

You can wrap functions and write like this with the following wrapping class:

var sale = new Sale();

await sale
    .Checkout()
    .AddTotal()
    .AddTax()
    .SetStatus(SaleStatus.Closed);
internal static class Wrappers
{
    public static Chain<Sale> Checkout(this Sale sale, CancellationToken cancellationToken = default)
    {
        return sale.ToChain(cancellationToken)
            .SetStatus(SaleStatus.Closing);
    }

    public static Chain<Sale> SetStatus(this Chain<Sale> chain, SaleStatus status)
    {
        return chain.AddNode(sale =>
        {
            sale.Status = status;
            return sale;
        });
    }

    public static Chain<Sale> AddTotal(this Chain<Sale> chain)
    {
        return chain.AddNode(sale =>
        {
            sale.Total = sale.Products.Sum(x => x.Price);
            return sale;
        });
    }

    public static Chain<Sale> AddTax(this Chain<Sale> chain)
    {
        return chain.AddNode(sale =>
        {
            sale.Tax = sale.Total * 0.12;
            return sale;
        });
    }
}
Product Compatible and additional computed target framework versions.
.NET 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.
  • net8.0

    • 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
8.0.6 1,842 2/27/2024
8.0.5 738 2/5/2024
8.0.4 83 2/2/2024
8.0.3 180 2/1/2024
8.0.2 75 1/31/2024
8.0.1 84 1/31/2024