Nabs.Launchpad.Core.Activities 10.0.219

Prefix Reserved
dotnet add package Nabs.Launchpad.Core.Activities --version 10.0.219
                    
NuGet\Install-Package Nabs.Launchpad.Core.Activities -Version 10.0.219
                    
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="Nabs.Launchpad.Core.Activities" Version="10.0.219" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Nabs.Launchpad.Core.Activities" Version="10.0.219" />
                    
Directory.Packages.props
<PackageReference Include="Nabs.Launchpad.Core.Activities" />
                    
Project file
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 Nabs.Launchpad.Core.Activities --version 10.0.219
                    
#r "nuget: Nabs.Launchpad.Core.Activities, 10.0.219"
                    
#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 Nabs.Launchpad.Core.Activities@10.0.219
                    
#: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=Nabs.Launchpad.Core.Activities&version=10.0.219
                    
Install as a Cake Addin
#tool nuget:?package=Nabs.Launchpad.Core.Activities&version=10.0.219
                    
Install as a Cake Tool

Nabs Launchpad Core Activities Library

The Nabs Launchpad Core Activities library provides a robust workflow execution framework for building structured, multi-step business processes in .NET applications. This library enables developers to create composable, testable, and maintainable workflows through a step-based execution model with built-in validation and dependency injection support.

Key Features

  • Step-Based Workflow Execution: Build complex workflows by composing individual activity steps that execute sequentially
  • Synchronous and Asynchronous Support: Support for both sync (ActivityStep<T>) and async (ActivityStepAsync<T>) step execution
  • Built-In Validation: Integrate FluentValidation validators as workflow steps with automatic validation result handling
  • Dependency Injection: Automatic constructor parameter resolution through service provider integration
  • Immutable Step Registration: Steps are registered during activity construction ensuring workflow consistency
  • State Management: Strongly-typed state objects that flow through the entire workflow execution
  • Function Steps: Support for simple function-based steps alongside class-based activity steps
  • Execution Context: Rich context object providing access to state, validation results, and configuration options
  • Cancellation Support: Built-in cancellation token support for long-running workflows
  • Error Handling: Comprehensive exception handling with custom ActivityStepExecutionException

Core Components

IActivity<TActivityState> and Activity<TActivityState>

The base interface and abstract class for defining workflows. Activities are composed of multiple steps that execute sequentially. Steps are registered in the RegisterSteps() method during construction.

IActivityStep

Marker interface for activity steps with completion tracking and reset capabilities.

ActivityStep<TActivityState>

Abstract base class for synchronous workflow steps. Implement the Run method to define step logic.

ActivityStepAsync<TActivityState>

Abstract base class for asynchronous workflow steps. Implement the RunAsync method to define step logic.

ActivityContext<TActivityState>

Provides execution context including:

  • Current state (State)
  • Validation results (ValidationResult)
  • Activity options (Options)

IActivityContext<TActivityState>

Interface for activity context, enabling testability and abstraction.

ActivityFactory

Factory class for creating activity instances with proper dependency injection setup. Manages global ActivityOptions configuration.

ActivityOptions

Configuration class containing the service provider used for dependency injection in activity steps.

IActivityState

Marker interface for strongly-typed state objects that flow through workflow execution.

Usage Examples

Basic Activity Definition

// Define your state
public class OrderProcessingState : IActivityState
{
    public int OrderId { get; set; }
    public decimal Amount { get; set; }
    public bool IsValidated { get; set; }
    public bool IsProcessed { get; set; }
    public bool IsNotified { get; set; }
}

// Create synchronous activity step
public class ValidateOrderStep : ActivityStep<OrderProcessingState>
{
    public override void Run(ActivityContext<OrderProcessingState> context)
    {
        // Validation logic
        if (context.State.Amount > 0)
        {
            context.State.IsValidated = true;
            IsCompleted = true;
        }
    }
}

// Create asynchronous activity step
public class ProcessPaymentStep : ActivityStepAsync<OrderProcessingState>
{
    private readonly IPaymentService _paymentService;
    
    public ProcessPaymentStep(IPaymentService paymentService)
    {
        _paymentService = paymentService;
    }
    
    public override async Task RunAsync(ActivityContext<OrderProcessingState> context)
    {
        await _paymentService.ProcessAsync(context.State.OrderId, context.State.Amount);
        context.State.IsProcessed = true;
        IsCompleted = true;
    }
}

// Define your workflow
public class OrderProcessingActivity : Activity<OrderProcessingState>
{
    protected override void RegisterSteps()
    {
        AddActivityStep<ValidateOrderStep>();
        AddValidatorStep<OrderValidator>();
        AddActivityStepAsync<ProcessPaymentStep>();
        AddFunctionStep(async () => {
            // Send notification logic
            await Task.Delay(100);
        });
    }
}

Executing Activities

// Setup dependency injection
var services = new ServiceCollection();
services.AddScoped<IPaymentService, PaymentService>();
var serviceProvider = services.BuildServiceProvider();

// Create activity factory with options
var factory = new ActivityFactory(options => {
    options.ServiceProvider = serviceProvider;
});

// Create and execute the activity
var activity = factory.Create<OrderProcessingActivity>();
await activity.ProcessAsync(state => {
    state.OrderId = 12345;
    state.Amount = 99.99m;
});

// Check results
if (activity.Context.ValidationResult?.IsValid == false)
{
    // Handle validation errors
    foreach (var error in activity.Context.ValidationResult.Errors)
    {
        Console.WriteLine($"{error.PropertyName}: {error.ErrorMessage}");
    }
}
else
{
    // Access final state
    Console.WriteLine($"Order {activity.Context.State.OrderId} processed successfully");
}

Using FluentValidation

// Define validator
public class OrderValidator : AbstractValidator<OrderProcessingState>
{
    public OrderValidator()
    {
        RuleFor(x => x.OrderId).GreaterThan(0);
        RuleFor(x => x.Amount).GreaterThan(0).WithMessage("Amount must be positive");
    }
}

// Add to activity
protected override void RegisterSteps()
{
    AddValidatorStep<OrderValidator>();
    // ... other steps
}

Function-Based Steps

protected override void RegisterSteps()
{
    // Simple inline step
    AddFunctionStep(async () => {
        await Task.Delay(100);
        Console.WriteLine("Simple step executed");
    });
    
    // Access to closures
    AddFunctionStep(async () => {
        var service = ActivityFactory.Options.ServiceProvider
            .GetRequiredService<IMyService>();
        await service.DoSomethingAsync();
    });
}

Cancellation Support

var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));

await activity.ProcessAsync(
    state => { state.OrderId = 12345; },
    cts.Token
);

API Reference

Activity<TActivityState>

Properties
Context
public ActivityContext<TActivityState> Context { get; }

Gets the execution context containing state and validation results.

Methods
ProcessAsync
public async ValueTask ProcessAsync(
    Action<TActivityState> stateSetup,
    CancellationToken cancellationToken = default)

Executes the activity workflow with the provided state setup.

Parameters:

  • stateSetup: Action to configure the initial state
  • cancellationToken: Optional cancellation token
RegisterSteps (Abstract)
protected abstract void RegisterSteps()

Override this method to register activity steps. Called during construction.

AddActivityStep<TActivityStep>
protected void AddActivityStep<TActivityStep>()
    where TActivityStep : ActivityStep<TActivityState>

Registers a synchronous activity step.

AddActivityStepAsync<TActivityStep>
protected void AddActivityStepAsync<TActivityStep>()
    where TActivityStep : ActivityStepAsync<TActivityState>

Registers an asynchronous activity step.

AddValidatorStep<TValidator>
protected void AddValidatorStep<TValidator>()
    where TValidator : class, IValidator<TActivityState>

Registers a FluentValidation validator as a step.

AddFunctionStep
protected void AddFunctionStep(Func<Task> action)

Registers a function-based step.

ActivityStep<TActivityState>

Properties
IsCompleted
public bool IsCompleted { get; protected set; }

Indicates whether the step has completed execution.

Methods
Run (Abstract)
public abstract void Run(ActivityContext<TActivityState> context)

Execute the step logic. Set IsCompleted = true when done.

Reset
public virtual void Reset()

Resets the step to its initial state. Override to add custom reset logic.

ActivityStepAsync<TActivityState>

Properties
IsCompleted
public bool IsCompleted { get; protected set; }

Indicates whether the step has completed execution.

Methods
RunAsync (Abstract)
public abstract Task RunAsync(ActivityContext<TActivityState> context)

Execute the asynchronous step logic. Set IsCompleted = true when done.

Reset
public virtual void Reset()

Resets the step to its initial state. Override to add custom reset logic.

ActivityContext<TActivityState>

Properties
State
public TActivityState State { get; set; }

The current workflow state.

ValidationResult
public ValidationResult? ValidationResult { get; set; }

Validation results from validator steps, if any.

Options
public ActivityOptions Options { get; }

Global activity options containing the service provider.

ActivityFactory

Constructor
public ActivityFactory(Action<ActivityOptions> configure)

Creates a factory with the specified configuration.

Methods
Create<TActivity>
public TActivity Create<TActivity>() where TActivity : IActivity, new()

Creates an instance of the specified activity type.

ActivityOptions

Properties
ServiceProvider
public IServiceProvider ServiceProvider { get; set; }

Service provider used for dependency injection in activity steps.

Architecture and Design Patterns

Step Registration and Immutability

Steps must be registered in the RegisterSteps() method during construction. After construction, the step list becomes immutable, ensuring workflow consistency and thread safety.

Dependency Injection

Activity steps can declare constructor dependencies that are automatically resolved from the configured service provider. This enables proper separation of concerns and testability.

Validation Integration

FluentValidation validators can be added as steps. If validation fails, workflow execution stops and validation results are available in Context.ValidationResult.

State Management

State flows through all steps via the ActivityContext. Steps can read and modify state, enabling communication between steps.

Error Handling

Activities throw ActivityStepExecutionException when a step fails to execute. The exception wraps the underlying exception and provides context about which step failed.

try
{
    await activity.ProcessAsync(state => { /* setup */ });
}
catch (ActivityStepExecutionException ex)
{
    Console.WriteLine($"Step failed: {ex.Message}");
    Console.WriteLine($"Inner exception: {ex.InnerException?.Message}");
}

Best Practices

  1. Keep Steps Focused: Each step should have a single, well-defined responsibility
  2. Use Validation Steps: Add validator steps early in the workflow to fail fast
  3. Manage State Carefully: State is shared across all steps; document state contracts
  4. Set IsCompleted: Always set IsCompleted = true in your step implementation when done
  5. Use Dependency Injection: Declare step dependencies in constructors rather than using service locator pattern
  6. Handle Cancellation: Long-running steps should periodically check the cancellation token
  7. Immutable Registration: Register all steps in RegisterSteps() method only

Testing

The library includes comprehensive unit tests demonstrating various usage patterns:

  • Synchronous activity execution
  • Asynchronous activity execution
  • Validation step integration with FluentValidation
  • HTTP client activity steps with dependency injection
  • Function-based steps
  • Bad dependency injection scenarios

Testing Your Activities

[Fact]
public async Task OrderProcessing_ValidOrder_Success()
{
    // Arrange
    var services = new ServiceCollection();
    services.AddScoped<IPaymentService, MockPaymentService>();
    var factory = new ActivityFactory(options => {
        options.ServiceProvider = services.BuildServiceProvider();
    });
    
    var activity = factory.Create<OrderProcessingActivity>();
    
    // Act
    await activity.ProcessAsync(state => {
        state.OrderId = 1;
        state.Amount = 100m;
    });
    
    // Assert
    activity.Context.State.IsProcessed.Should().BeTrue();
    activity.Context.ValidationResult?.IsValid.Should().BeTrue();
}

Dependencies

  • Ardalis.Result: For result pattern implementation and error handling
  • Ardalis.Result.FluentValidation: Integration layer between Ardalis.Result and FluentValidation
  • FluentValidation: For validation step support and rule-based validation
  • Microsoft.EntityFrameworkCore: For data access scenarios in activity steps
  • Microsoft.Extensions.Http: For HTTP client integration in activity steps

Target Framework

  • .NET 10
Product 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.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
10.0.219 43 1/5/2026
10.0.218 44 1/4/2026
10.0.217 39 1/4/2026
10.0.216 41 1/4/2026
10.0.215 43 1/4/2026
10.0.214 47 1/1/2026
10.0.213 82 1/1/2026 10.0.213 is deprecated because it is no longer maintained.
10.0.212 54 1/1/2026 10.0.212 is deprecated because it is no longer maintained.
10.0.211 57 12/31/2025 10.0.211 is deprecated because it is no longer maintained.
10.0.210 77 12/30/2025 10.0.210 is deprecated because it is no longer maintained.
10.0.209 92 12/30/2025 10.0.209 is deprecated because it is no longer maintained.
10.0.208 98 12/30/2025 10.0.208 is deprecated because it is no longer maintained.
10.0.207 95 12/29/2025 10.0.207 is deprecated because it is no longer maintained.
10.0.206 95 12/29/2025 10.0.206 is deprecated because it is no longer maintained.
10.0.205 185 12/24/2025 10.0.205 is deprecated because it is no longer maintained.
10.0.204 181 12/21/2025 10.0.204 is deprecated because it is no longer maintained.
10.0.203 276 12/18/2025 10.0.203 is deprecated because it is no longer maintained.
10.0.202 279 12/17/2025 10.0.202 is deprecated because it is no longer maintained.
10.0.200 283 12/17/2025 10.0.200 is deprecated because it is no longer maintained.
10.0.199 427 12/10/2025 10.0.199 is deprecated because it is no longer maintained.
10.0.197 169 12/5/2025 10.0.197 is deprecated because it is no longer maintained.
10.0.196 679 12/3/2025 10.0.196 is deprecated because it is no longer maintained.
10.0.195 678 12/3/2025 10.0.195 is deprecated because it is no longer maintained.
10.0.194 678 12/3/2025 10.0.194 is deprecated because it is no longer maintained.
10.0.193 687 12/2/2025 10.0.193 is deprecated because it is no longer maintained.
10.0.192 181 11/28/2025 10.0.192 is deprecated because it is no longer maintained.
10.0.190 204 11/27/2025 10.0.190 is deprecated because it is no longer maintained.
10.0.189 175 11/23/2025 10.0.189 is deprecated because it is no longer maintained.
10.0.187 176 11/23/2025 10.0.187 is deprecated because it is no longer maintained.
10.0.186 166 11/23/2025 10.0.186 is deprecated because it is no longer maintained.
10.0.184 411 11/20/2025 10.0.184 is deprecated because it is no longer maintained.
10.0.181-rc3 297 11/11/2025 10.0.181-rc3 is deprecated because it is no longer maintained.
10.0.180 300 11/11/2025 10.0.180 is deprecated because it is no longer maintained.
10.0.179-rc2 251 11/11/2025 10.0.179-rc2 is deprecated because it is no longer maintained.
10.0.178-rc2 217 11/10/2025 10.0.178-rc2 is deprecated because it is no longer maintained.
10.0.177-rc2 204 11/10/2025 10.0.177-rc2 is deprecated because it is no longer maintained.
10.0.176-rc2 166 11/6/2025 10.0.176-rc2 is deprecated because it is no longer maintained.
10.0.175-rc2 165 11/6/2025 10.0.175-rc2 is deprecated because it is no longer maintained.
10.0.174-rc2 181 11/5/2025 10.0.174-rc2 is deprecated because it is no longer maintained.
10.0.173-rc2 236 11/3/2025 10.0.173-rc2 is deprecated because it is no longer maintained.
10.0.172-rc2 179 11/2/2025 10.0.172-rc2 is deprecated because it is no longer maintained.
10.0.170-rc2 177 11/1/2025 10.0.170-rc2 is deprecated because it is no longer maintained.
10.0.169-rc2 165 11/1/2025 10.0.169-rc2 is deprecated because it is no longer maintained.
10.0.168-rc2 163 10/31/2025 10.0.168-rc2 is deprecated because it is no longer maintained.
10.0.166-rc2 168 10/31/2025 10.0.166-rc2 is deprecated because it is no longer maintained.
10.0.164-rc2 232 10/28/2025 10.0.164-rc2 is deprecated because it is no longer maintained.
10.0.162-rc2 234 10/24/2025 10.0.162-rc2 is deprecated because it is no longer maintained.
9.0.151 210 10/17/2025 9.0.151 is deprecated because it is no longer maintained.
9.0.150 284 9/10/2025 9.0.150 is deprecated because it is no longer maintained.
9.0.146 223 8/15/2025 9.0.146 is deprecated because it is no longer maintained.
9.0.145 282 8/11/2025 9.0.145 is deprecated because it is no longer maintained.
9.0.144 282 8/8/2025 9.0.144 is deprecated because it is no longer maintained.
9.0.137 248 7/29/2025 9.0.137 is deprecated because it is no longer maintained.