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
<PackageReference Include="Nabs.Launchpad.Core.Activities" Version="10.0.219" />
<PackageVersion Include="Nabs.Launchpad.Core.Activities" Version="10.0.219" />
<PackageReference Include="Nabs.Launchpad.Core.Activities" />
paket add Nabs.Launchpad.Core.Activities --version 10.0.219
#r "nuget: Nabs.Launchpad.Core.Activities, 10.0.219"
#:package Nabs.Launchpad.Core.Activities@10.0.219
#addin nuget:?package=Nabs.Launchpad.Core.Activities&version=10.0.219
#tool nuget:?package=Nabs.Launchpad.Core.Activities&version=10.0.219
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 statecancellationToken: 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
- Keep Steps Focused: Each step should have a single, well-defined responsibility
- Use Validation Steps: Add validator steps early in the workflow to fail fast
- Manage State Carefully: State is shared across all steps; document state contracts
- Set IsCompleted: Always set
IsCompleted = truein your step implementation when done - Use Dependency Injection: Declare step dependencies in constructors rather than using service locator pattern
- Handle Cancellation: Long-running steps should periodically check the cancellation token
- 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 | 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. |
-
net10.0
- Ardalis.Result (>= 10.1.0)
- Ardalis.Result.FluentValidation (>= 10.1.0)
- FluentValidation (>= 12.1.1)
- Microsoft.EntityFrameworkCore (>= 10.0.1)
- Microsoft.Extensions.Http (>= 10.0.1)
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.212 | 54 | 1/1/2026 | |
| 10.0.211 | 57 | 12/31/2025 | |
| 10.0.210 | 77 | 12/30/2025 | |
| 10.0.209 | 92 | 12/30/2025 | |
| 10.0.208 | 98 | 12/30/2025 | |
| 10.0.207 | 95 | 12/29/2025 | |
| 10.0.206 | 95 | 12/29/2025 | |
| 10.0.205 | 185 | 12/24/2025 | |
| 10.0.204 | 181 | 12/21/2025 | |
| 10.0.203 | 276 | 12/18/2025 | |
| 10.0.202 | 279 | 12/17/2025 | |
| 10.0.200 | 283 | 12/17/2025 | |
| 10.0.199 | 427 | 12/10/2025 | |
| 10.0.197 | 169 | 12/5/2025 | |
| 10.0.196 | 679 | 12/3/2025 | |
| 10.0.195 | 678 | 12/3/2025 | |
| 10.0.194 | 678 | 12/3/2025 | |
| 10.0.193 | 687 | 12/2/2025 | |
| 10.0.192 | 181 | 11/28/2025 | |
| 10.0.190 | 204 | 11/27/2025 | |
| 10.0.189 | 175 | 11/23/2025 | |
| 10.0.187 | 176 | 11/23/2025 | |
| 10.0.186 | 166 | 11/23/2025 | |
| 10.0.184 | 411 | 11/20/2025 | |
| 10.0.181-rc3 | 297 | 11/11/2025 | |
| 10.0.180 | 300 | 11/11/2025 | |
| 10.0.179-rc2 | 251 | 11/11/2025 | |
| 10.0.178-rc2 | 217 | 11/10/2025 | |
| 10.0.177-rc2 | 204 | 11/10/2025 | |
| 10.0.176-rc2 | 166 | 11/6/2025 | |
| 10.0.175-rc2 | 165 | 11/6/2025 | |
| 10.0.174-rc2 | 181 | 11/5/2025 | |
| 10.0.173-rc2 | 236 | 11/3/2025 | |
| 10.0.172-rc2 | 179 | 11/2/2025 | |
| 10.0.170-rc2 | 177 | 11/1/2025 | |
| 10.0.169-rc2 | 165 | 11/1/2025 | |
| 10.0.168-rc2 | 163 | 10/31/2025 | |
| 10.0.166-rc2 | 168 | 10/31/2025 | |
| 10.0.164-rc2 | 232 | 10/28/2025 | |
| 10.0.162-rc2 | 234 | 10/24/2025 | |
| 9.0.151 | 210 | 10/17/2025 | |
| 9.0.150 | 284 | 9/10/2025 | |
| 9.0.146 | 223 | 8/15/2025 | |
| 9.0.145 | 282 | 8/11/2025 | |
| 9.0.144 | 282 | 8/8/2025 | |
| 9.0.137 | 248 | 7/29/2025 |