Beskar.CodeGeneration.ProcessorGenerator
1.1.9
There is a newer version of this package available.
See the version list below for details.
See the version list below for details.
dotnet add package Beskar.CodeGeneration.ProcessorGenerator --version 1.1.9
NuGet\Install-Package Beskar.CodeGeneration.ProcessorGenerator -Version 1.1.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="Beskar.CodeGeneration.ProcessorGenerator" Version="1.1.9" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Beskar.CodeGeneration.ProcessorGenerator" Version="1.1.9" />
<PackageReference Include="Beskar.CodeGeneration.ProcessorGenerator" />
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 Beskar.CodeGeneration.ProcessorGenerator --version 1.1.9
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Beskar.CodeGeneration.ProcessorGenerator, 1.1.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 Beskar.CodeGeneration.ProcessorGenerator@1.1.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=Beskar.CodeGeneration.ProcessorGenerator&version=1.1.9
#tool nuget:?package=Beskar.CodeGeneration.ProcessorGenerator&version=1.1.9
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Beskar.CodeGeneration.ProcessorGenerator
A source generator for creating efficient, type-safe processing pipelines. It automates the boilerplate of chaining processors and managing execution flow.
What it does
- Generates Pipeline Execution: Creates an
Execute(orExecuteAsync) method that chains processors in a defined order. - Dependency Injection Integration: Generates a
GetFactory(IServiceProvider)method to resolve and configure the pipeline and its processors from a DI container. - Context Management: Provides a
ProcessorContextto share state across processors within a single execution. - Timeout Support: Built-in support for execution timeouts via
CancellationToken. - Post-Processing: Supports cleanup or logging logic via
Postmethods that run after the main execution.
How it works
- Define Processors: Implement
ISyncProcessor,IAsyncProcessor, orIValueAsyncProcessorand mark them with[Processor]. - Define a Pipeline: Create a
partial classmarked with[ProcessorPipeline]. - Add Steps: Add properties to your pipeline class for each processor and mark them with
[Step(order)]. - Configure Settings: Use
[Setting]attributes on steps to inject values into processor properties during initialization.
Example
[Processor]
internal sealed class MainProcessor : ISyncProcessor<string, int>
{
public Result<int, ProcessorError> Execute(
ProcessorContext context, string input, CancellationToken cancellationToken)
{
return int.TryParse(input, out var result)
? result
: new ProcessorError("Invalid integer input");
}
}
...
[Processor]
internal sealed class LogProcessor<TIn> : IValueAsyncProcessor<TIn, TIn>, IValueAsyncPostProcessor
{
public async ValueTask<Result<TIn, ProcessorError>> Execute(
ProcessorContext context, TIn input, CancellationToken cancellationToken)
{
Console.WriteLine($"Starting Pipeline: {context.PipelineName}");
return input;
}
public ValueTask<ProcessorError?> Post(
ProcessorContext context, CancellationToken cancellationToken)
{
Console.WriteLine($"Ending Pipeline: {context.PipelineName}, took {context.Elapsed}");
return ValueTask.FromResult<ProcessorError?>(null);
}
}
internal class LoggablePipeline
{
[Step(0)]
public required LogProcessor<int> Log { get; set; }
}
[Timeout(500)]
[ContextVariable<string>("MyString")]
[ContextVariable<int>("MyInt")]
[ContextVariable<object>("MyObject")]
internal class BasePipeline<TValueProcessor> : LoggablePipeline
{
[Step(1)]
[Setting(nameof(ValueProcessor.ArraySetting), new [] { "Test1", "Test2" })]
public required TValueProcessor First { get; set; }
[Step(2)]
[Setting(nameof(AsyncProcessor.Delay), 1_000)]
[Setting(nameof(AsyncProcessor.PostMessage), "Setting Post Message")]
public required AsyncProcessor Second { get; set; }
}
[ProcessorPipeline("Main")]
[Timeout(1000)]
[ContextVariable<bool>("MyBool")]
internal sealed partial class MainPipeline : BasePipeline<ValueProcessor>
{
[Step(3)]
public required MainProcessor Third { get; set; }
}
How to use it?
var serviceCollection = new ServiceCollection();
serviceCollection.AddScoped<MainProcessor>()
.AddScoped<AsyncProcessor>()
.AddScoped<ValueProcessor>()
.AddScoped(typeof(LogProcessor<>));
serviceCollection.AddScoped(MainPipeline.GetFactory);
var provider = serviceCollection.BuildServiceProvider();
var pipeline = provider.GetRequiredService<MainPipeline>();
await pipeline.Execute(123, CancellationToken.None);
What is being generated?
internal sealed partial class MainPipeline
{
public static global::Beskar.CodeGeneration.ProcessorGenerator.Tests.Scenarios.Simple.MainPipeline GetFactory(IServiceProvider provider)
{
var pipeline = new global::Beskar.CodeGeneration.ProcessorGenerator.Tests.Scenarios.Simple.MainPipeline()
{
Third = provider.GetService(typeof(global::Beskar.CodeGeneration.ProcessorGenerator.Tests.Scenarios.Simple.MainProcessor)) as global::Beskar.CodeGeneration.ProcessorGenerator.Tests.Scenarios.Simple.MainProcessor
?? throw new InvalidOperationException("Cannot resolve global::Beskar.CodeGeneration.ProcessorGenerator.Tests.Scenarios.Simple.MainProcessor"),
First = provider.GetService(typeof(global::Beskar.CodeGeneration.ProcessorGenerator.Tests.Scenarios.Simple.ValueProcessor)) as global::Beskar.CodeGeneration.ProcessorGenerator.Tests.Scenarios.Simple.ValueProcessor
?? throw new InvalidOperationException("Cannot resolve global::Beskar.CodeGeneration.ProcessorGenerator.Tests.Scenarios.Simple.ValueProcessor"),
Second = provider.GetService(typeof(global::Beskar.CodeGeneration.ProcessorGenerator.Tests.Scenarios.Simple.AsyncProcessor)) as global::Beskar.CodeGeneration.ProcessorGenerator.Tests.Scenarios.Simple.AsyncProcessor
?? throw new InvalidOperationException("Cannot resolve global::Beskar.CodeGeneration.ProcessorGenerator.Tests.Scenarios.Simple.AsyncProcessor"),
Log = provider.GetService(typeof(global::Beskar.CodeGeneration.ProcessorGenerator.Tests.Scenarios.Simple.LogProcessor<int>)) as global::Beskar.CodeGeneration.ProcessorGenerator.Tests.Scenarios.Simple.LogProcessor<int>
?? throw new InvalidOperationException("Cannot resolve global::Beskar.CodeGeneration.ProcessorGenerator.Tests.Scenarios.Simple.LogProcessor<int>"),
};
pipeline.First.ArraySetting = ["Test1", "Test2"];
pipeline.Second.Delay = 1000;
pipeline.Second.PostMessage = "Setting Post Message";
return pipeline;
}
public async Task<Result<int, ProcessorError>> Execute(int input, CancellationToken ct)
{
ProcessorContext context = new MainPipelineContext()
{
PipelineName = "Main"
};
using var cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
cts.CancelAfter(1000);
ct = cts.Token;
var r1 = await Log.Execute(context, input, ct);
if (!r1.HasValue) return r1.Error;
var r2 = await First.Execute(context, r1.Success, ct);
if (!r2.HasValue) return r2.Error;
var r3 = await Second.Execute(context, r2.Success, ct);
if (!r3.HasValue) return r3.Error;
var r4 = Third.Execute(context, r3.Success, ct);
if (!r4.HasValue) return r4.Error;
var error1 = await Second.Post(context, ct);
if (error1 is not null) return error1;
var error2 = await Log.Post(context, ct);
if (error2 is not null) return error2;
return r4.Success;
}
public sealed class MainPipelineContext : ProcessorContext
{
public bool MyBool { get; set; }
public string? MyString { get; set; }
public int MyInt { get; set; }
public object? MyObject { get; set; }
}
}
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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.
-
net10.0
- Beskar.CodeGeneration.ProcessorGenerator.Marker (>= 1.1.9)
- Me.Memory (>= 1.3.7)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.