FluxFlow.Components.Storage 3.0.9

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

FluxFlow.Components.Storage

Standalone storage nodes for FluxFlow: blockified put/get/query/delete over an injected IStorageStore. No engine required.

Each node is a self-contained TPL Dataflow processor built on FluxFlow.Nodes. Every message travels as a FlowMessage<T> envelope (payload + correlation id), so the correlation id flows request → result for free — and onto the Found/NotFound and Records branches. The host owns the IStorageStore lifetime and injects the opened store into each node; the nodes never open or dispose it (exactly like the HTTP node over an HttpClient).

Nodes

Node Shape Purpose
StoragePutNode Input → Output, Errors, Events Stores or updates a logical record.
StorageGetNode Input → Output, Found, NotFound, Errors, Events Reads a logical record and fans found/missing results.
StorageQueryNode Input → Output, Records, Errors, Events Queries records by collection, key prefix, attributes, time bounds, and limit.
StorageDeleteNode Input → Output, Errors, Events Deletes a logical record and reports whether it existed.
// The host owns the store; the node just borrows it.
IStorageStore store = ...;
await using var put = new StoragePutNode(store);

var request = FlowMessage.Create(new StoragePutRequest
{
    Collection = "items",
    Key = "a",
    Value = "one"
});
await put.Input.SendAsync(request);

var result = await put.Output.ReceiveAsync();      // FlowMessage<StorageResult>
// result.CorrelationId == request.CorrelationId   // the envelope carries it

Output, Found, NotFound, Records, Errors, and Events are all broadcast ports — link each to as many downstream consumers as you like.

Put

await using var put = new StoragePutNode(store, new StoragePutOptions
{
    Collection = "items",
    Mode = StorageWriteMode.Upsert,
    EmitStoredRecord = true,
    BoundedCapacity = 128
});

StoragePutNode consumes StoragePutRequest and emits StorageResult. Supported modes are Upsert, Create, and Replace. The request can override the node mode per item. Unsupported per-message write modes are reported as InvalidRequest errors and later messages continue processing.

Get

await using var get = new StorageGetNode(store, new StorageGetOptions
{
    Collection = "items",
    IncludeExpired = false
});

StorageGetNode consumes StorageGetRequest and emits StorageResult on Output. Found records are also fanned to Found; missing records are also fanned to NotFound. A missing record is a normal result, not a processing error.

Query

await using var query = new StorageQueryNode(store, new StorageQueryOptions
{
    Collection = "items",
    Offset = 0,
    Limit = 100,
    IncludeExpired = false,
    EmitRecordsInResult = true,
    EmitRecordOutputs = true
});

StorageQueryNode consumes StorageQueryRequest and emits one StorageQueryResult on Output. The Records port emits each returned StorageRecord (as a FlowMessage<StorageRecord>) when EmitRecordOutputs is true. Requests can filter by collection, key prefix, exact-match attributes, stored time bounds, expired-record policy, offset, and limit.

Delete

await using var delete = new StorageDeleteNode(store, new StorageDeleteOptions
{
    Collection = "items",
    EmitMissingAsResult = true
});

StorageDeleteNode consumes StorageDeleteRequest and emits StorageResult. Missing deletes can be emitted as normal results or suppressed (EmitMissingAsResult).

Errors and events

A store failure or an invalid request surfaces a FlowError on Errors (stamped with the in-flight correlation id and a Code from StorageErrorCodes) and the node keeps processing later messages. Each node also emits FlowEvent diagnostics on Events (names in StorageDiagnosticNames).

Store Ownership

The package does not include a concrete database. A host supplies an IStorageStore — see the FileSystem and SqlFile adapter packages — and injects it into the nodes.

Adapter packages register a store factory through StorageComponentOptions:

var options = new StorageComponentOptions()
    .UseFileSystemStorage("./data");      // adapter extension
IStorageStore store = (await options.StoreFactory
    .OpenAsync(new StorageStoreContext { StoreName = "items-db" })).Store;

StorageStoreLease.Owned(store) marks a store the lease should dispose; StorageStoreLease.Shared(store) marks a host-owned store that must not be disposed. The factory receives the store name, default collection, and clock through StorageStoreContext. Delegate-backed factories registered through StorageComponentOptions.UseStore(...) must return a non-null StorageStoreLease; shared-store delegates must return a non-null store. StorageStoreContext trims store names and default collections, treats blank values as absent, and falls back to TimeProvider.System when a null clock is assigned.

Runtime Timing

Each node uses System.TimeProvider (default TimeProvider.System) for result timestamps. Pass a deterministic TimeProvider (for example Microsoft.Extensions.Time.Testing.FakeTimeProvider) when tests, replay, or deterministic dashboards need stable timestamps:

await using var put = new StoragePutNode(store, clock: fakeTimeProvider);

The same clock can be supplied to a backend store through StorageStoreContext.Clock so stored records and expiration checks share one time source.

Contracts

Core contracts:

  • StoragePutRequest
  • StorageGetRequest
  • StorageQueryRequest
  • StorageDeleteRequest
  • StorageQueryResult
  • StorageResult
  • StorageRecord
  • StorageWriteMode
  • IStorageStore
  • IStorageStoreFactory
  • StorageStoreContext
  • StorageStoreLease

StorageRecord.Value is object?: hosts own serialization and can compose this package with serialization or payload components before storage.

Request contracts trim optional text fields such as collection, key prefix, content type, and correlation id, treating blank values as absent. Attribute dictionaries are copied on assignment, use ordinal key comparison, and treat null as empty. Nodes and stores still own required collection/key validation so invalid workflow messages surface as normal storage errors instead of constructor failures.

Output contracts follow the same rule: records and results trim textual identity/diagnostic fields, normalize blank optional values to absent, copy attribute dictionaries with ordinal key comparison, and copy query result record lists on assignment.

Node option records trim default collection names and treat blank collections as absent. Invalid capacities, query paging values, and write modes are rejected when options are assigned so direct-code and configuration-bound callers fail at the component boundary.

Composition

Building a workflow, reading config, creating nodes, and linking them is a separate concern from the node package. This package is just the standalone nodes and storage contracts.

Use FluxFlow.Components.Storage.Composition when a FluxFlow.Composition host should register the optional storage factories:

services.AddKeyedSingleton<IStorageStore>("items-store", store);

services
    .AddFluxFlowComposition(configuration)
    .RegisterNodes(registry => registry
        .RegisterStoragePut()
        .RegisterStorageGet()
        .RegisterStorageQuery()
        .RegisterStorageDelete());

The composition adapter binds the existing storage option records from node configuration, resolves the required store from the keyed store resource, and can resolve an optional keyed TimeProvider resource named clock. Concrete store setup still belongs to the host or backend adapter packages; the composition adapter only consumes an already registered IStorageStore.

The optional composition package also exposes StorageComponentDesignMetadataProvider for neutral Designer metadata over the storage composition node types. The standalone Storage package remains free of Designer, Composition, and Engine dependencies.

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 (3)

Showing the top 3 NuGet packages that depend on FluxFlow.Components.Storage:

Package Downloads
FluxFlow.Components.Storage.FileSystem

File-system-backed storage adapter for FluxFlow storage components.

FluxFlow.Components.Storage.SqlFile

Single-file SQL storage adapter for FluxFlow storage components.

FluxFlow.Components.Storage.Composition

Optional canonical exact-content storage registrations over host-owned keyed stores or factories.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
8.0.0-rc.1 110 9/5/2026
7.0.0 254 8/3/2026
3.0.10 181 7/3/2026
3.0.9 231 7/2/2026
3.0.0 170 6/19/2026
2.0.0 194 6/18/2026
1.1.0 484 6/5/2026
1.0.0 180 6/4/2026
0.4.0-alpha.1 85 6/3/2026
0.3.0-alpha.1 264 6/2/2026
0.2.1-alpha.1 100 6/2/2026
0.2.0-alpha.1 101 6/2/2026
0.1.0-alpha.1 98 6/1/2026

Storage put, query, and delete nodes now report clear failures when an injected store violates non-null result contracts.