NodePipeline.Reporting.Abstractions (2.0.0)

Published 2026-10-01 14:59:45 +00:00 by THE_KONDRAT in THE_KONDRAT/NodePipeline

Installation

dotnet nuget add source --name THE_KONDRAT --username your_username --password your_token 
dotnet add package --source THE_KONDRAT --version 2.0.0 NodePipeline.Reporting.Abstractions

About this package

Node pipeline reporting abstractions

NodePipeline

A pipeline library that executes a graph of nodes described in YAML. Nodes are plain C# classes; a source generator produces an AOT-safe factory/validator for them at compile time — no reflection at runtime.

Main idea

            node class (C#)                    pipeline graph (YAML)
        ┌───────────────────────┐
        │ [NodeField(Input)]    │     nodes:
        │   NodeField<Image> In │◀────  - id: load
        │ [NodeField(Parameter)]│          type: FileImageSource
        │   NodeField<int> Size │        outputs: [Out]
        │ [NodeField(Output)]   │      - id: blur
        │   NodeField<Image> Out│────▶     type: GaussianBlur
        │ void Execute() { ... }│          parameters: {Radius: 50}
        └───────────────────────┘          inputs: {Input: load.Out}
                      │
        compile time  ▼
        ┌─────────────────────────────┐
        │ source generator            │
        │  · GeneratedNodeFactory     │  switch: YAML type → new Node()
        │  · GeneratedNodeValidator   │  [Required], ranges, defaults
        │  · DI extensions (optional) │
        └─────────────────────────────┘
                      │
        runtime       ▼
        YamlGraphLoader → PipelineRegistry.Register(...) → validation
                              │
                              ▼
        registry.Build(factory, id) → connected node graph → Execute()

Data flows only through connected ports (NodeField<T>), scalars arrive via parameters. The engine itself is minimal: topological order + Execute() loop.

Quick example

Define a node:

public class GaussianBlurNode : INode
{
    [NodeField(FieldDirection.Input)] public NodeField<ImageBuffer> Input { get; set; } = null!;

    [NodeField(FieldDirection.Parameter)]
    [HasValueBetween(0, 300)]
    public NodeField<int> Radius { get; set; } = null!;

    [NodeField(FieldDirection.Output)] public NodeField<ImageBuffer> Output { get; set; } = null!;

    public void Execute()
    {
        var src = Input.Value;
        var dst = new ImageBuffer(src.Width, src.Height);
        Convolution.Apply(src, dst, GaussianKernel.Create(Radius.Value));
        Output.Value = dst;
    }
}

Describe the pipeline in YAML:

name: pipeline-1
nodes:
  - id: load_image
    type: FileImageSource
    parameters:
      FileName: { value: "input" }
    outputs: [Output]
  - id: blur
    type: GaussianBlur
    parameters:
      Radius: { value: 50 }
    inputs:
      Input: { source: load_image.Output }

Register, build and run:

using var yaml = File.OpenRead("p1.yaml");
var config = new YamlGraphLoader().Load(yaml);

var factory = new GeneratedNodeFactory();       // generated at compile time
var validator = new GeneratedNodeValidator();
var registry = new PipelineRegistry(CultureInfo.CurrentCulture);

registry.Register(factory, validator, config.Name, config);
var pipeline = registry.Build(factory, config.Name);
pipeline.Execute();

With DI (NodePipeline.Engine.DependencyInjection):

services.AddPipeline();   // factory, validator, registry + all nodes with DI constructors

await using var scope = provider.CreateAsyncScope();
var registry = scope.ServiceProvider.GetRequiredService<PipelineRegistry>();
var pipeline = registry.Build(scope.ServiceProvider.GetRequiredService<INodeFactory>(), "pipeline-1");
pipeline.Execute();

External resources

An input port can be bound to a named external resource instead of another node's output — use the resource: prefix in the connection source:

inputs:
  Photo: { source: "resource:logo" }

Pass an IPipelineResourceProvider at build time; the generated factory binds the value directly to the port. A required input whose resource is missing (or has an incompatible type) throws ResourceNotFoundException:

var pipeline = registry.Build(factory, config.Name, resources);

Resource connections create no graph edges and skip port-type validation at registration (the provider is only known at build time).

IDE analyzer

NodePipeline.Abstractions ships a Roslyn analyzer that catches node declaration mistakes while typing: NP1001 [NodeType] on a non-INode class, NP1002 [NodeField] on a non-NodeField<T> property, NP1003/NP1004 non-public node class or field, NP1005 validation attribute incompatible with the field type, NP1006 duplicate [NodeType] names (warning), NP1007 redundant [DisallowNullableOutput] on a nullable field (warning). Duplicate names across assemblies are also reported as NP0002 by the source generators.

Packages

Package Contents
NodePipeline.Abstractions INode, NodeField<T>, attributes, validators
NodePipeline.Configuration.Abstractions / .Yaml pipeline description model, YAML loader
NodePipeline.Engine runtime (graph, connectors, executor) + source generator
NodePipeline.Engine.DependencyInjection DI extensions + DI source generator
NodePipeline.Reporting.* registration reporting abstractions / console reporter

Build & publish order: see PUBLISHING.md.

Dependencies

ID Version Target Framework
NodePipeline.Abstractions 2.0.0 .NETStandard2.1
Details
NuGet
2026-10-01 14:59:45 +00:00
3
THE_KONDRAT
6.9 KiB
Assets (2)
Versions (3) View all
2.1.0 2026-10-01
2.0.0 2026-10-01
0.2.0 2026-03-03