Skip to content

Commit df63773

Browse files
authored
Create Documentation (#13)
* Remove landing page * Add documentation * Add project image assets
1 parent 91481c3 commit df63773

31 files changed

Lines changed: 620 additions & 604 deletions

CONTRIBUTING.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
# Contributing to PipeForge
22

3-
PipeForge has received lots of great feedback from the community. We've used this feedback to inform the direction of the project, and we absolutely want to keep hearing from you! **Your involvement makes the project better** by increasing the usability, quality and adoption of the project. Our goal is to be better stewards by being more responsive and transparent. Following the contribution guidelines outlined below will help us to better help you.
3+
Community feedback is used to inform the direction of the project, and we absolutely want to hear from you! **Your involvement makes the project better** by increasing the usability, quality and adoption of the project. Our goal is to be better stewards by being more responsive and transparent. Following the contribution guidelines outlined below will help us to better help you.
44

55
# How To Get Help
66

77
A lot of issues that were created in previous versions of PipeForge were not bugs or feature requests, they were questions or discussions - most of which could be (and were) answered by anyone in the community; they're not exclusive to the maintainers. For feedback like this, there are several places where people can get all kinds of help, and we would encourage you to use them first.
88

99
- Consult the [official documentation](https://scottoffen.github.io/PipeForge).
10-
- Take a gander at the [Samples](https://github.com/scottoffen/PipeForge/tree/main/src/Samples) project.
1110
- Engage in our [community discussions](https://github.com/scottoffen/PipeForge/discussions).
1211
- Ask your question on [StackOverflow](https://stackoverflow.com) using [#PipeForge](https://stackoverflow.com/questions/tagged/PipeForge?sort=newest).
1312

@@ -27,8 +26,6 @@ Regardless of whether you are opening a bug report, asking a question on StackOv
2726

2827
Got an idea on how to make PipeForge better? Start or join a conversation in our [community discussions](https://github.com/scottoffen/PipeForge/discussions) and suggest your change there. **Do not open an issue on GitHub until** you have collected positive feedback about the change. Where it comes to improvements, we want to ensure we are focused on solving problems, not attacking symptoms, while remaining focused on our guiding principles: fast, unopinionated, and minimalist. In a word: simple.
2928

30-
That being said, PipeForge is designed to make it easy to add middleware at different places in the server and request/response pipeline. You can also create your own implementations of the different interfaces and inject them. All told, that makes it easy to take your functionality and put it in a package that can be used by others as an add-on or plugin to the core PipeForge library, rather than in the core library, if that makes more sense.
31-
3229
If it is decided that your idea would be a good inclusion to the core PipeForge project, create a feature request issue based on the outcome of the community discussion.
3330

3431
# Issue Management
@@ -71,8 +68,8 @@ Changes that are cosmetic in nature and do not add anything substantial to the s
7168
- It creates a lot of notification noise
7269
- It pollutes the git history
7370

74-
Sometimes, your editor will completely reformat a file when you save it, making numerous white space changes that, while they don't affect the code, create a lot of noise for the reviewers. If this happens, the PR will not be considered until those white space changes are removed.
71+
Sometimes, your editor may completely reformat a file when you save it, making numerous white space changes that, while they don't affect the code, create a lot of noise for the reviewers. If this happens, the PR will not be considered until those white space changes are reverted.
7572

7673
# Documentation Changes
7774

78-
Having excellent documentation is crucial to the success of PipeForge. Documentation for PipeForge lives in [docs](). Your contribution of clear, concise and accurate documentation is appreciated.
75+
Having excellent documentation is crucial to the success of PipeForge. Documentation for PipeForge is written using [Docusaurus](https://docusaurus.io/), lives in [docs folder](./docs/). Your contribution of clear, concise and accurate documentation is appreciated.

docs/docs/describe-pipelines.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
sidebar_position: 6
3+
title: Describing Pipelines
4+
---
5+
6+
# Describing Pipelines
7+
8+
The `Describe()` method on `IPipelineRunner<T>` is used to inspect and document the pipeline configuration at runtime. It returns a JSON string describing each registered pipeline step.
9+
10+
This method is useful for diagnostics, tooling, and dynamically displaying pipeline behavior in user interfaces or logs - but only if you've taken the time to add the necessary metadata to your step classes.
11+
12+
## Output Format
13+
14+
The JSON output contains an array of objects, each representing a pipeline step with the following fields:
15+
16+
* `Order`: The zero-based order in which the step appears in the pipeline
17+
* `Name`: The value of the step's `Name` property
18+
* `Description`: The step's `Description`, if defined
19+
* `MayShortCircuit`: A boolean indicating whether the step might short-circuit execution
20+
* `ShortCircuitCondition`: The value of the step's `ShortCircuitCondition`, if any
21+
22+
Example output:
23+
24+
```json
25+
[
26+
{
27+
"Order": 0,
28+
"Name": "ValidateInput",
29+
"Description": "Checks that required values are present",
30+
"MayShortCircuit": true,
31+
"ShortCircuitCondition": "Invalid input"
32+
},
33+
{
34+
"Order": 1,
35+
"Name": "TransformData",
36+
"Description": "Prepares data for downstream steps",
37+
"MayShortCircuit": false,
38+
"ShortCircuitCondition": null
39+
}
40+
]
41+
```
42+
43+
## Instantiation Behavior
44+
45+
Calling `Describe()` **will instantiate all steps** in the pipeline by accessing their `Lazy<T>` wrappers. This may result in constructor injection or other side effects associated with instantiating the step class. Use this method only when you are prepared for that overhead.
46+
47+
## Use Cases
48+
49+
* Logging pipeline structure for observability
50+
* Generating runtime documentation or UI
51+
* Verifying step order and metadata during tests or builds
52+
53+
If you need to inspect step configuration without triggering instantiation, consider maintaining parallel metadata or restricting usage of `Describe()` to controlled environments.
54+
55+
## Conclusion
56+
57+
Use `Describe()` to introspect your pipeline at runtime, but be aware that it will force full resolution of every registered step.

docs/docs/diagnostics.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
sidebar_position: 8
3+
title: Diagnostics
4+
---
5+
6+
# Diagnostics
7+
8+
PipeForge includes built-in diagnostics via the [`System.Diagnostics.DiagnosticSource`](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.diagnosticsource) API. This allows you to observe pipeline execution without modifying your steps.
9+
10+
## Emitted Events
11+
12+
The pipeline emits the following diagnostic events for each step:
13+
14+
| Event Name | Description |
15+
| -------------------- | ---------------------------------------------------------------- |
16+
| `PipelineStep.Start` | Emitted **before** a step is invoked. Payload includes the step. |
17+
| `PipelineStep.Stop` | Emitted **after** a step completes. Payload includes the step. |
18+
19+
All events are emitted under a listener name in the format:
20+
21+
```
22+
PipeForge.PipelineRunner<TContext>
23+
```
24+
25+
You can subscribe to these events to monitor or trace execution flow.
26+
27+
## Example: Listening for Events
28+
29+
Here's an example of a diagnostic listener that logs every start and stop event:
30+
31+
```csharp
32+
using System.Diagnostics;
33+
34+
var listener = new DiagnosticListener("PipeForge.PipelineRunner<SampleContext>");
35+
listener.Subscribe(new Observer((name, payload) =>
36+
{
37+
Console.WriteLine($"{name}: {payload}");
38+
}));
39+
```
40+
41+
## Integration Tips
42+
43+
* You can use this mechanism to generate timing metrics, debug issues, or visualize step execution.
44+
* Diagnostic events are low-overhead and safe to leave enabled in production.
45+
* Combine this with the `Describe()` method for a full picture of pipeline structure and execution behavior.
46+
47+
## Conclusion
48+
49+
PipeForge diagnostics give you deep visibility into pipeline execution with minimal effort. Whether you’re debugging a failing step or building runtime instrumentation, the diagnostics hooks are ready to help.

docs/docs/index.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
sidebar_position: 1
3+
title: Getting Started
4+
---
5+
6+
# Welcome to PipeForge
7+
8+
PipeForge is a lightweight, composable, lazy-instantiation pipeline framework for .NET. It simplifies step-based processing while remaining discoverable and testable. Inspired by middleware pipelines and modern dependency injection patterns, PipeForge gives you structured control over sequential logic flows - without the ceremony.
9+
10+
Pipelines operate on a specific class known as the **context**. Each pipeline step is a discrete unit of work, written in code and annotated with metadata indicating its order and (optional) environment. These steps are lazily instantiated and executed in sequence by the pipeline runner.
11+
12+
At any point, the pipeline can **short-circuit**, halting execution — and preventing the instantiation of any remaining steps.
13+
14+
## Sample Context
15+
16+
For the purposes of this documentation, the following sample context will be used.
17+
18+
```csharp title="SampleContext.cs"
19+
public class SampleContext
20+
{
21+
private readonly List<string> _steps = new();
22+
23+
public void AddStep(string stepName)
24+
{
25+
if (string.IsNullOrWhiteSpace(stepName))
26+
{
27+
throw new ArgumentException("Step name cannot be null or whitespace.", nameof(stepName));
28+
}
29+
30+
_steps.Add(stepName);
31+
}
32+
33+
public int StepCount => _steps.Count;
34+
35+
public override string ToString()
36+
{
37+
return string.Join(",", _steps);
38+
}
39+
}
40+
```
41+
42+
This context allows us to:
43+
- Track pipeline progress via AddStep()
44+
- Print execution history using ToString()
45+
- Assert how many steps ran using StepCount
46+
- Simulate errors by passing invalid step names
47+
48+
## Installation
49+
50+
PipeForge is available on [NuGet.org](https://www.nuget.org/packages/PipeForge/) and can be installed using a NuGet package manager or the .NET CLI.
51+
52+
PipeForge targets `.NET Standard 2.0` for broad compatibility, and also multi-targets `.NET 5.0` to take advantage of modern runtime features where available.

docs/docs/intro.md

Lines changed: 0 additions & 47 deletions
This file was deleted.

docs/docs/manual-wiring.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
sidebar_position: 7
3+
title: Manual Wiring
4+
---
5+
6+
# Using PipeForge Without Dependency Injection
7+
8+
PipeForge is designed to integrate smoothly with dependency injection, but it's flexible enough to be used without it. Manual wiring may be useful in testing scenarios, lightweight environments, or when you want full control over pipeline composition.
9+
10+
## Manually Constructing a Pipeline
11+
12+
You can manually create a list of steps and pass them to a `PipelineRunner<T>`. Each step should be wrapped in a `Lazy<IPipelineStep<T>>` to maintain compatibility with PipeForge's lazy instantiation pattern.
13+
14+
```csharp title="Manual Pipeline Setup"
15+
public class StepA : PipelineStep<SampleContext>
16+
{
17+
public StepA() => Name = "A";
18+
19+
public override async Task InvokeAsync(SampleContext context, PipelineDelegate<SampleContext> next, CancellationToken cancellationToken = default)
20+
{
21+
context.AddStep(Name);
22+
await next(context, cancellationToken);
23+
}
24+
}
25+
26+
public class StepB : PipelineStep<SampleContext>
27+
{
28+
public StepB() => Name = "B";
29+
30+
public override async Task InvokeAsync(SampleContext context, PipelineDelegate<SampleContext> next, CancellationToken cancellationToken = default)
31+
{
32+
context.AddStep(Name);
33+
await next(context, cancellationToken);
34+
}
35+
}
36+
37+
public class StepC : PipelineStep<SampleContext>
38+
{
39+
public StepShortCircuit() => Name = "C";
40+
41+
public override Task InvokeAsync(SampleContext context, PipelineDelegate<SampleContext> next, CancellationToken cancellationToken = default)
42+
{
43+
context.AddStep(Name);
44+
await next(context, cancellationToken);
45+
}
46+
}
47+
48+
var steps = new List<Lazy<IPipelineStep<SampleContext>>>
49+
{
50+
new(() => new StepA()),
51+
new(() => new StepC()),
52+
new(() => new StepB())
53+
};
54+
55+
var runner = new PipelineRunner<SampleContext>(steps);
56+
57+
var context = new SampleContext();
58+
await runner.ExecuteAsync(context);
59+
60+
Console.WriteLine($"Final context: {context}");
61+
```
62+
63+
## Conclusion
64+
65+
Manual wiring allows you to build and run a pipeline without relying on a DI container. While this approach is less common for production use, it provides maximum control for testing and minimal-host scenarios.

0 commit comments

Comments
 (0)