Context Object
A context is a per-run “session object” that carries “input” + “options” + “output sinks” through a workflow, without turning everything into global state
What is it
A context is an object created once per “run”. It holds run-specific data like config, input, and output sinks, or even request specific information like OrgId. Components read from it and write to it, but they don’t own it.
public sealed class Context
{
public SourceDocument Source { get; }
public Options Options { get; }
public IDiagnosticsSink Diagnostics { get; }
public Context(SourceDocument source, Options options, IDiagnosticsSink diagnostics)
{
Source = source;
Options = options;
Diagnostics = diagnostics;
}
}When to use
Best used for pipelines with multiple steps that require the same run-specific information, such as the input, per-run options, and a place to record diagnostics.
You should really scope contexts based on a group of related services; this helps mitigate the “god object” problem.
What to include?
Put things into context when they should differ between two runs happening at the same time, like source/input, per-run options (mode, limits), cancellation token, run id, and per-run output sinks (diagnostics collector, metrics for this run).
What not to include?
Do not put stable services into context, like loggers, localisers, keyword tables, and global configuration; those should be injected into the components that need them. While a logger is a sink its cannot be included because it is not run specific.
Trade-offs
Pros
- Clear separation between per-run state and stable services
- Easy to run concurrently
- Makes tests simpler because you can pass a context with a fake diagnostics sink
- Avoids “ambient” hidden dependencies; scales well as the pipeline grows
Cons
- Can become a “god object” if you keep adding unrelated stuff
- It hides real dependencies and makes code harder to reason about