Skip to content

Source Generators

The Strategos.Generators package transforms fluent DSL definitions into type-safe artifacts at compile time.

Generated Artifacts Overview

ArtifactPurpose
Phase EnumType-safe enumeration of workflow phases
CommandsWolverine message types for step transitions
EventsMarten event types for audit trail
Saga ClassComplete Wolverine saga with handlers
State ReducersProperty merge logic based on attributes
DI ExtensionsService registration helpers

Phase Enum

Generated enumeration representing all workflow phases.

Generation Pattern

For a workflow named process-order with steps ValidateOrder, ProcessPayment, FulfillOrder:

csharp
// Generated
public enum ProcessOrderPhase
{
    NotStarted,
    ValidateOrder,
    ProcessPayment,
    FulfillOrder,
    Completed,
    Failed
}

Special Values

ValueDescription
NotStartedInitial state before workflow begins
CompletedTerminal state after successful completion
FailedTerminal state after failure

Commands

Generated Wolverine command types for triggering step execution.

Generation Pattern

csharp
// Generated for each step
public record ExecuteValidateOrderCommand(
    [property: SagaIdentity] Guid WorkflowId);

public record ExecuteProcessPaymentCommand(
    [property: SagaIdentity] Guid WorkflowId);

public record ExecuteFulfillOrderCommand(
    [property: SagaIdentity] Guid WorkflowId);

Attributes

AttributePurpose
[SagaIdentity]Links command to saga instance

Events

Generated Marten event types for audit trail.

Generation Pattern

csharp
// Workflow lifecycle events
public record ProcessOrderWorkflowStarted(Guid WorkflowId, DateTimeOffset Timestamp);
public record ProcessOrderWorkflowCompleted(Guid WorkflowId, DateTimeOffset Timestamp);

// Phase transition events
public record ProcessOrderPhaseChanged(
    Guid WorkflowId,
    ProcessOrderPhase FromPhase,
    ProcessOrderPhase ToPhase,
    DateTimeOffset Timestamp);

// Step completion events
public record ValidateOrderStepCompleted(
    Guid WorkflowId,
    DateTimeOffset Timestamp,
    OrderState StateSnapshot);

Event Properties

PropertyTypeDescription
WorkflowIdGuidWorkflow instance identifier
TimestampDateTimeOffsetWhen the event occurred
FromPhaseEnumPrevious phase (for transitions)
ToPhaseEnumNew phase (for transitions)
StateSnapshotTStateState at completion (for step events)

Saga Class

Generated Wolverine saga containing all handlers.

Generation Pattern

csharp
// Generated saga
public partial class ProcessOrderSaga : Saga
{
    public Guid WorkflowId { get; set; }
    public OrderState State { get; set; }
    public ProcessOrderPhase Phase { get; set; }

    // Entry point
    public async Task<ExecuteValidateOrderCommand> Start(
        StartProcessOrderCommand command,
        CancellationToken ct)
    {
        WorkflowId = command.WorkflowId;
        State = command.InitialState;
        Phase = ProcessOrderPhase.ValidateOrder;
        return new ExecuteValidateOrderCommand(WorkflowId);
    }

    // Step handlers
    public async Task<ExecuteProcessPaymentCommand> Handle(
        ExecuteValidateOrderCommand command,
        ValidateOrderStep step,
        CancellationToken ct)
    {
        var result = await step.ExecuteAsync(State, CreateContext(), ct);
        State = ProcessOrderStateReducer.Reduce(State, result.State);
        Phase = ProcessOrderPhase.ProcessPayment;
        return new ExecuteProcessPaymentCommand(WorkflowId);
    }

    // Additional handlers...
}

Saga Properties

PropertyTypeDescription
WorkflowIdGuidSaga identity
StateTStateCurrent workflow state
PhaseEnumCurrent workflow phase

State Reducers

Generated logic for merging state updates based on attributes.

Generation Pattern

csharp
// For state with [Append] and [Merge] attributes
public static class ProcessOrderStateReducer
{
    public static OrderState Reduce(OrderState current, OrderState update)
    {
        return current with
        {
            // Regular properties: take update value
            Status = update.Status ?? current.Status,
            TotalAmount = update.TotalAmount,

            // [Append] properties: combine lists
            AuditLog = current.AuditLog
                .Concat(update.AuditLog ?? Enumerable.Empty<string>())
                .ToList(),

            // [Merge] properties: combine dictionaries
            Metadata = current.Metadata
                .Concat(update.Metadata ?? new())
                .GroupBy(kv => kv.Key)
                .ToDictionary(g => g.Key, g => g.Last().Value)
        };
    }
}

Merge Behaviors

AttributeBehavior
(none)Update replaces current
[Append]Lists are concatenated
[Merge]Dictionaries are combined, newer wins

DI Extensions

Generated service registration helpers.

Generation Pattern

csharp
// Generated extension method
public static class ProcessOrderWorkflowExtensions
{
    public static IServiceCollection AddProcessOrderWorkflow(
        this IServiceCollection services)
    {
        // Register step implementations
        services.AddScoped<ValidateOrderStep>();
        services.AddScoped<ProcessPaymentStep>();
        services.AddScoped<FulfillOrderStep>();

        // Register saga
        services.AddScoped<ProcessOrderSaga>();

        return services;
    }
}

Usage

csharp
services.AddStrategos()
    .AddProcessOrderWorkflow();

// Or add all workflows in assembly
services.AddStrategos()
    .AddWorkflowsFromAssembly(typeof(ProcessOrderWorkflow).Assembly);

Triggering Generation

Generation is triggered by the [Workflow] attribute on a class containing a workflow definition.

Required Pattern

csharp
using Strategos;

namespace MyApp.Workflows;

[Workflow("process-order")]
public static partial class ProcessOrderWorkflow
{
    public static WorkflowDefinition<OrderState> Definition =>
        Workflow<OrderState>.Create("process-order")
            .StartWith<ValidateOrderStep>()
            .Then<ProcessPaymentStep>()
            .Finally<FulfillOrderStep>();
}

Requirements

RequirementDescription
[Workflow] attributeTriggers source generation
partial modifierAllows generator to extend class
static modifierWorkflow definitions are static
NamespaceCannot be in global namespace

Generated File Location

Generated files appear in the obj directory and are visible in IDE under Dependencies > Analyzers:

text
obj/
  Debug/
    net8.0/
      generated/
        Strategos.Generators/
          ProcessOrderWorkflow.g.cs
          ProcessOrderSaga.g.cs
          ProcessOrderStateReducer.g.cs

Viewing Generated Code

In Visual Studio, expand Dependencies > Analyzers > Strategos.Generators to see generated files. In Rider, use Navigate > Generated Code.

Released under the MIT License.