AAurora Workflows
Get started
Documentation

Fluent API

Build, configure, and run workflows entirely in .NET code

Overview

The Aurora Workflows Fluent API (Aurora.Workflows.Fluent, targeting .NET Standard 2.0) lets you construct complete workflows in C# without using the designer. The API is chainable: every method returns a builder so calls can be composed in a single expression.

The entry point is the static class FluentWorkflow.

Getting Started

using Aurora.Workflows.Fluent;
using Aurora.Workflows.Tasks;

var workflow = FluentWorkflow
    .Create("Hello World")
    .TriggerOnce()
    .Print("Hello, Aurora Workflows!")
    .Build();

await workflow.StartAsync();

FluentWorkflow (Entry Point)

MethodDescription
FluentWorkflow.Create(name, loggerFactory?)Creates a new workflow builder. A root StartTask is created automatically.
FluentWorkflow.Load(json, loggerFactory?)Restores a workflow from a JSON string previously produced by Persist().

FluentWorkflowBuilder – Metadata & Triggers

MethodDescription
.WithName(name)Sets or overrides the workflow display name.
.WithTags(params string[] tags)Adds classification tags to the workflow.
.ConfigureWorkflow(action)Applies an arbitrary action on the underlying IWorkflow.
.TriggerOnce()Adds a OneTimeTrigger so the workflow runs exactly once.
.TriggerPeriodic(interval, tolerance?)Adds a TimedTrigger with the given interval and optional jitter.
.TriggerOnSchedule(cronExpression, name?)Adds a CronTrigger. Uses Quartz.NET cron syntax.
.TriggerOnFileChange(path, filter?, name?)Adds a FileTrigger watching the given directory.
.AddTrigger(trigger)Adds any pre-constructed IWorkflowTaskTriggerBase instance.
.AddTrigger<TTrigger>(configure?)Creates, optionally configures, and adds a typed trigger.
.RemoveTrigger(trigger)Removes a trigger from the workflow.

FluentWorkflowBuilder – Task Shortcuts

The builder exposes the most common task operations directly. All of these delegate to the root StartTask and return a FluentWorkflowTaskBuilder scoped to the newly added task.

MethodDescription
.Do<TTask>(configure?)Adds a typed task as a child of the root.
.Do(task)Adds a pre-constructed task.
.Print(text, color?, name?)Adds a DebugOutputTask with a static string.
.PrintExpression(expr, color?, name?)Adds a DebugOutputTask whose message is a Roslyn expression.
.SetVariable(varName, expression, name?)Adds a SetVariableTask.
.Set(varName, expression, name?)Alias for SetVariable.
.ReadFile(filePath, outputVar?, name?)Adds a ReadFileTask with a static path.
.ReadFileExpression(expr, outputVar?, name?)Adds a ReadFileTask whose path is a Roslyn expression.
.WriteFile(filePath, inputVar?, append?, name?)Adds a WriteFileTask with a static path.
.WriteFileExpression(expr, inputVar?, append?, name?)Adds a WriteFileTask with a dynamic path.
.Wait(duration, name?)Adds a WaitTask.
.If(expression, then, else?, name?)Adds a runtime if/else branch (see below).
.Switch(configure, name?)Adds a multi-way switch (see below).
.Loop(expression, body, name?)Adds a LoopTask (see below).
.ForEach(collectionExpression, body, elementVariableName?, name?)Adds a ForEachTask iterating over an IEnumerable; the current item is exposed to the body via elementVariableName (or as the task output).
.Async(name?, useThreadPool?)Adds an AsyncTask scope.
.Throttle(interval, body, persistenceId?, name?)Adds a TimeThrottledScope.
.OnChange(expression, body, persistenceId?, name?)Adds a ChangeDetectedScope.

FluentWorkflowTaskBuilder – Chaining

After adding a task you receive a FluentWorkflowTaskBuilder scoped to that task. Its API mirrors FluentWorkflowBuilder and adds:

Method / PropertyDescription
.ThenProperty that returns the builder unchanged, used for readability (.Then.Print(…)).
.Named(name)Sets the name of the most recently added task.
.WithOutput(varName)Sets CustomOutputVariableName on the task.
.WithInput(varName)Sets CustomInputVariableName.
.UseGlobalScopeForOutput()Sets UseGlobalScopeForOutput = true.
.UseGlobalScopeForInput()Sets UseGlobalScopeForInput = true.
.Retry(interval, maxRetries)Enables retry with the given interval and count.
.IgnoreErrors()Sets ContinueOnError = true.
.Parallel(params tasks[])Adds pre-built tasks as parallel branches.
.AddBranchTask(task)Adds a single parallel branch task.
.Synchronize(name?)Adds a MergeTask that waits for all preceding parallel branches (AND-gate).
.Build()Finalizes and returns the IWorkflow.
.Persist()Serializes the workflow to JSON and returns the string.
Task ExecuteAsync()Builds and immediately runs the workflow.

Runtime Branching: If / Else

FluentWorkflow.Create("Branching Demo")
    .TriggerOnce()
    .Set("hour", "DateTime.Now.Hour")
    .If("hour < 12",
        then: t => t.Print("Good morning!"),
        @else: e => e.Print("Good afternoon/evening!"),
        name: "Time Check")
    .Then.Print("Done.")
    .Build();

Runtime Branching: Switch

FluentWorkflow.Create("Switch Demo")
    .TriggerOnce()
    .Set("score", "42")
    .Switch(sw => sw
        .Case("score >= 90", b => b.Print("Grade: A"))
        .Case("score >= 70", b => b.Print("Grade: B"))
        .Default(b => b.Print("Grade: F")),
        "Grade Evaluation")
    .Build();

Loops

FluentWorkflow.Create("Loop Demo")
    .TriggerOnce()
    .Set("counter", "0").UseGlobalScopeForOutput()
    .Loop("counter < 5", body => body
        .Set("counter", "counter + 1")
            .UseGlobalScopeForInput()
            .UseGlobalScopeForOutput()
        .Then.PrintExpression("$\"Iteration {counter}\""))
    .Then.Print("Done.")
    .Build();

Parallel Branches and Merge

FluentWorkflow.Create("Parallel Demo")
    .TriggerOnce()
    .Do<StartTask>(t => t.Name = "Fan-Out")
    .Parallel(
        new ReadFileTask { FileName = "file1.txt", Name = "Read 1" },
        new ReadFileTask { FileName = "file2.txt", Name = "Read 2" })
    .Synchronize("Wait for all reads")
    .Then.Print("All reads complete.")
    .Build();

Extension Methods

The FluentWorkflowExtensions class adds higher-order helpers on top of FluentWorkflowTaskBuilder:

MethodDescription
.Chain(params tasks[])Adds multiple pre-built tasks sequentially. Returns a builder scoped to the last task.
.Repeat<TTask>(count, (task, index) => {})Adds count instances of a typed task sequentially, calling the configure callback for each.
.ForEach<TTask, TItem>(items, (task, item) => {})Adds one typed task per item in the collection, configured with that item.
.Parallel<TTask>(count, (task, index) => {})Adds count instances of a typed task as parallel branches.
.Group(name, configure)Wraps a set of tasks inside a named StartTask container.
.Apply(configure)Invokes an action on the builder and returns it, useful for extracting reusable configuration snippets.
.When(condition, configure)Applies the configure action only if condition is true at build time.
.When(condition, whenTrue, whenFalse)Build-time conditional with both branches.
.DoIf<TTask>(condition, configure?)Adds the task only if condition is true at build time.
Build-time vs. runtime: .When() and .DoIf() evaluate their condition when the workflow is being constructed, not when it executes. For runtime branching use .If() or .Switch().

Persisting and Reloading

// Persist to JSON
string json = FluentWorkflow.Create("My Workflow")
    .TriggerOnce()
    .Print("Hello")
    .Persist();

File.WriteAllText("my-workflow.awf", json);

// Reload and run
var workflow = FluentWorkflow.Load(File.ReadAllText("my-workflow.awf")).Build();
await workflow.StartAsync();