LightPath.Cargo 3.0.6

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

Cargo

A lightweight Chain of Responsibility pipeline library for .NET.

NuGet

Why Would I Use This?

You have a series of steps that process or transform data — validation, enrichment, persistence, notification — and you want each step to be:

  • Isolated — each step is its own class with a single responsibility
  • Composable — mix, match, and reorder steps without touching their internals
  • Testable — test each step independently
  • Flexible — support sync and async work, error handling, retries, and early termination

Cargo gives you this with minimal ceremony. Define your steps as stations, wire them into a bus, and go.

Common use cases:

  • Request processing pipelines
  • Validation chains
  • ETL / data transformation
  • Workflow orchestration
  • Multi-step form processing

Installation

dotnet add package LightPath.Cargo

Quick Start

Define a content model (the data that flows through the pipeline):

public class OrderContext
{
    public string CustomerId { get; set; }
    public decimal Total { get; set; }
    public bool IsValid { get; set; }
    public bool IsProcessed { get; set; }
}

Create stations (each step in the pipeline):

public class ValidateOrder : Station<OrderContext>
{
    public override Station.Action Process()
    {
        Package.Contents.IsValid = Package.Contents.Total > 0
                                && !string.IsNullOrEmpty(Package.Contents.CustomerId);

        return Package.Contents.IsValid
            ? Station.Action.Next()
            : Station.Action.Abort("Invalid order");
    }
}

public class ProcessOrder : Station<OrderContext>
{
    public override Station.Action Process()
    {
        Package.Contents.IsProcessed = true;
        return Station.Action.Next();
    }
}

Wire them up and run:

var context = new OrderContext { CustomerId = "C-123", Total = 49.99m };

var result = Bus.New<OrderContext>()
    .WithStation<ValidateOrder>()
    .WithStation<ProcessOrder>()
    .Go(context);

// context.IsValid == true
// context.IsProcessed == true

Features

  • Sync and async stationsStation<T> for synchronous work, StationAsync<T> for async/IO-bound work
  • Mixed pipelines — freely interleave sync and async stations in the same pipeline
  • Services — register and inject dependencies into stations
  • Error handling — abort on error (default) or continue with error state
  • Station repeat — stations can repeat themselves until a condition is met
  • Final station — a station that always runs, even after an abort
  • Cancellation — pass a CancellationToken to GoAsync(), accessible via Package.CancellationToken
  • Tracing — built-in trace messages for pipeline execution
  • Result tracking — inspect results from each station via Package.Results
  • Multi-target — supports net472, net48, net6.0, net7.0, net8.0

Core Concepts

Package — wraps your content model and carries it through the pipeline. Holds results, services, trace messages, and error state.

Station — a single step in the pipeline. Receives the package, does its work, and returns an action: Next(), Abort(), or Repeat().

Bus — builds and executes the pipeline. You register stations, services, and configuration, then call Go() or GoAsync().

Examples

Async Stations

public class FetchCustomerData : StationAsync<OrderContext>
{
    public override async Task<Station.Action> ProcessAsync()
    {
        var service = GetService<ICustomerApi>();
        var customer = await service.GetCustomerAsync(Package.Contents.CustomerId);

        Package.Contents.CustomerName = customer.Name;
        return Station.Action.Next();
    }
}

var result = await Bus.New<OrderContext>()
    .WithService<ICustomerApi>(customerApi)
    .WithStation<ValidateOrder>()
    .WithStation<FetchCustomerData>()
    .WithStation<ProcessOrder>()
    .GoAsync(context);

Async stations run with the caller's synchronization context. Cargo uses ConfigureAwait(false) internally, but station authors control their own awaits — standard .NET async guidance applies.

Services

Register dependencies and access them from any station:

var bus = Bus.New<OrderContext>()
    .WithService<ICustomerApi>(customerApi)
    .WithService<ILogger>(logger)
    .WithStation<FetchCustomerData>();

// Inside a station:
var api = GetService<ICustomerApi>();
var logger = GetService<ILogger>();

// Or safely:
if (TryGetService<ILogger>(out var logger))
{
    logger.Log("Processing order");
}

Error Handling

By default, an exception in a station aborts the pipeline:

var bus = Bus.New<OrderContext>()
    .WithStation<RiskyStation>()
    .WithStation<NextStation>()
    .WithFinalStation<CleanupStation>();

// If RiskyStation throws, NextStation is skipped, CleanupStation runs.

To continue after errors:

var bus = Bus.New<OrderContext>()
    .WithNoAbortOnError()
    .WithStation<RiskyStation>()
    .WithStation<NextStation>();

// If RiskyStation throws, NextStation still runs.
// Check Package.IsErrored or LastResult.WasFailure to inspect error state.

Station Repeat

A station can repeat itself until a condition is met:

public class RetryableStation : Station<OrderContext>
{
    public override Station.Action Process()
    {
        Package.Contents.Attempts++;

        if (Package.Contents.Attempts < 3)
            return Station.Action.Repeat();

        return Station.Action.Next();
    }
}

Set a repeat limit to prevent infinite loops (default is 100):

var bus = Bus.New<OrderContext>()
    .WithStationRepeatLimit(10)
    .WithStation<RetryableStation>();

Cancellation

var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));

var result = await Bus.New<OrderContext>()
    .WithStation<SlowStation>()
    .GoAsync(context, cts.Token);

// Inside a station, access the token:
// Package.CancellationToken

Cancellation is checked between stations. If the token is cancelled, the pipeline throws OperationCanceledException and skips all remaining stations, including the final station.

Abort with Messages

return Station.Action.Abort("Payment declined");

// Later:
bus.Package.AbortMessage // "Payment declined"
bus.Package.IsAborted    // true

API Reference

Bus

Method Description
Bus.New<T>() Create a new bus
.WithStation<TStation>() Add a station to the pipeline
.WithStations(params Type[]) Add multiple stations by type
.WithFinalStation<TStation>() Set a station that runs after abort or error
.WithService<T>(T service) Register a typed service
.WithServices(strategy, params object[]) Register multiple services
.WithAbortOnError() Abort pipeline on station error (default)
.WithNoAbortOnError() Continue pipeline on station error
.WithStationRepeatLimit(int) Set max repeat iterations (default: 100)
.Go(content, callback?) Execute the pipeline synchronously
.GoAsync(content, token?, callback?) Execute the pipeline asynchronously

Station.Action

Method Description
Next() Proceed to the next station
Next(string) Proceed with a message
Next(Exception) Proceed with an exception
Abort() Abort the pipeline
Abort(string) Abort with a message
Abort(Exception) Abort with an exception
Repeat() Repeat the current station
Repeat(string) Repeat with a message
Repeat(Exception) Repeat with an exception

Station Members

Member Description
Package The current package
Package.Contents The content model
Package.CancellationToken The cancellation token (async pipelines)
IsErrored Whether any station has errored
LastResult The result from the previous station
PackageResults All station results so far
Messages Trace messages
GetService<T>() Get a registered service
HasService<T>() Check if a service is registered
TryGetService<T>(out T) Safely get a service
Trace(string) Add a trace message

Target Frameworks

  • .NET Framework 4.7.2
  • .NET Framework 4.8
  • .NET 6.0
  • .NET 7.0
  • .NET 8.0

License

MIT - LightPath Solutions, LLC

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.  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 Framework net472 is compatible.  net48 is compatible.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETFramework 4.7.2

    • No dependencies.
  • .NETFramework 4.8

    • No dependencies.
  • net6.0

    • No dependencies.
  • net7.0

    • No dependencies.
  • 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
3.0.6 88 3/20/2026
2.0.4.7 442 6/2/2025
2.0.4.6 216 5/3/2025
2.0.4.4 318 2/19/2025
2.0.4.3 235 2/19/2025
2.0.4.2 240 2/18/2025
2.0.4.1 223 2/14/2025
2.0.3.6 2,165 1/7/2024
2.0.3.5 267 1/7/2024
2.0.3.4 253 1/7/2024
2.0.3.3 266 1/7/2024
2.0.3.2 259 1/7/2024
2.0.3.1 3,408 9/29/2022
2.0.3 633 9/22/2022
2.0.2.6 637 9/4/2022
2.0.2.5 549 9/4/2022
2.0.2.4 541 9/4/2022
2.0.2.3 556 9/2/2022
2.0.2.2 560 9/2/2022
2.0.2.1 547 9/2/2022
Loading failed