FluxFlow.Fluent 4.0.0

There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package FluxFlow.Fluent --version 4.0.0
                    
NuGet\Install-Package FluxFlow.Fluent -Version 4.0.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="FluxFlow.Fluent" Version="4.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FluxFlow.Fluent" Version="4.0.0" />
                    
Directory.Packages.props
<PackageReference Include="FluxFlow.Fluent" />
                    
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 FluxFlow.Fluent --version 4.0.0
                    
#r "nuget: FluxFlow.Fluent, 4.0.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.
#:package FluxFlow.Fluent@4.0.0
                    
#: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=FluxFlow.Fluent&version=4.0.0
                    
Install as a Cake Addin
#tool nuget:?package=FluxFlow.Fluent&version=4.0.0
                    
Install as a Cake Tool

FluxFlow.Fluent

Type-safe, code-first fluent DSL for composing FluxFlow.Nodes.

Use this package when you want to wire standalone nodes into a runnable graph in C# with the compiler checking every connection, instead of canonical string/JSON application links. It reuses the FluxFlow.Composition runtime for lifecycle, error/event aggregation, and disposal.

Why

Flow.From(...).Then(...).To(...) reads as a pipeline, and the generic type parameter tracks the payload type flowing between nodes: Then only accepts a node whose input matches the current output, so a mis-wired graph is a compile error, not a runtime diagnostic. The FlowMessage<T> envelope stays hidden — you work in payload types.

Boundary

FluxFlow.Fluent owns:

  • the fluent builder (Flow, FlowBuilder<T>, FlowTerminal)
  • compile-time-checked linear chains, fan-out (Tap), branching (Branch from a typed output port), and fan-in (share one node instance across branches)
  • the built FlowGraph (start, stop, completion, error/event streams, disposal)

It does not own node implementations, the runtime, a component catalog, JSON/config loading, or persistence — nodes come from FluxFlow.Nodes (and the component packages), and the runtime comes from FluxFlow.Composition.

Capacity configuration

The fluent graph API links node instances that have already been constructed; it does not apply a second graph-wide capacity setting. Custom nodes pass their capacity to the base type explicitly:

public sealed class WordSource : FlowSource<string>
{
    public WordSource(IReadOnlyList<string> words)
        : base(new FlowSourceOptions { OutputCapacity = 256 })
    {
        // Store words for RunAsync.
    }
}

public sealed class UppercaseNode : FlowNode<string, string>
{
    public UppercaseNode()
        : base(new FlowNodeOptions
        {
            InputCapacity = 64,
            OutputCapacity = 128
        })
    {
    }

    // ProcessAsync omitted.
}

Component-package nodes expose their own immutable options. In the canonical application DSL, the corresponding component builders use BoundedCapacity or a domain-specific name. Engine FluxFlowApplicationOptions.OutputCapacity is a separate stable-port setting and never overrides these node capacities.

Linear pipeline

await using var flow = Flow
    .From(new WordSource(["alpha", "beta"]))   // FlowSource<string>
    .Then(new UppercaseNode())                 // FlowNode<string, string>
    .To(new CollectSink(collector))            // FlowNode<string, _>
    .Build();

await flow.StartAsync();
await flow.Completion;

Fan-out, branching, and fan-in

var sink = new CollectSink(collector);
var router = new EvenOddRouter();              // FlowNode<int, int> with Even/Odd ports

await using var flow = Flow
    .From(new CountSource(6))
    .Then(router)
    .Tap(new AuditNode())                                          // fan-out, main line unchanged
    .Branch(router.Even, even => even.Then(new LabelNode("even")).To(sink))
    .Branch(router.Odd,  odd  => odd.Then(new LabelNode("odd")).To(sink))  // both fan into one sink
    .Build();

await flow.StartAsync();
await flow.Completion;

Branches share the flow's graph; passing the same node instance to Then/To in more than one branch fans them into that node. Each node completes once all of its upstream sources finish, so fan-in drains correctly rather than being completed early by the first branch.

Observing errors and events

await using var flow = Flow
    .From(new WordSource(["alpha", "beta"]))
    .Then(new RiskyNode())
    .To(new CollectSink(collector))
    .OnError(error => logger.LogError(error.Exception, "{Message}", error.Message))
    .OnEvent(@event => logger.LogInformation("{Name}", @event.Name))
    .Build();

OnError/OnEvent observe the flow's aggregated error/event streams. They are also available on the built FlowGraph (returning an IDisposable you can dispose to unsubscribe). Observation is best-effort (the underlying stream is a latest-wins broadcast), a throwing handler is isolated so it cannot break observation, and subscriptions are torn down with the graph.

Reusable named sub-flows

var normalize = FlowSegment.Define<string, string>("normalize",
    b => b.Then(new TrimNode()).Then(new UppercaseNode()));

await using var flow = Flow
    .From(new WordSource(["  alpha ", "beta"]))
    .Apply(normalize)          // splice the segment in
    .To(new CollectSink(collector))
    .Build();

A FlowSegment<TIn, TOut> is a named, typed fragment you define once and splice into any flow with Apply. It holds the build delegate, not node instances, so each application constructs fresh nodes — the same segment is safe to reuse across graphs and to apply more than once.

Sample

dotnet run --project samples/FluxFlow.FluentSample/FluxFlow.FluentSample.csproj
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.  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 is compatible.  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. 
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 FluxFlow.Fluent:

Package Downloads
FluxFlow.Fluent.Hosting

Optional hosting bridge for FluxFlow.Fluent: register a FlowGraph with AddFlowGraph and run it as an IHostedService — built and started on host start, stopped and disposed on shutdown. The factory delegate resolves nodes from DI.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
5.0.0-rc.1 61 8/9/2026
4.0.0 134 8/3/2026
1.2.0 111 7/4/2026
1.1.0 138 7/3/2026
1.0.0 108 7/3/2026

Updates the code-first graph surface for the canonical-only Composition dependency.