FlexibleStrategyFramework.Extensions.DynamicScripting 1.1.0

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

Flexible Strategy Framework

Ask DeepWiki

A generic, domain-independent strategy pattern framework for .NET designed for building complex, maintainable, and extensible business logic pipelines. It provides robust support for sequential and parallel execution, dynamic scripting with JavaScript and Lua, automatic dependency injection registration via source generators, and built-in monitoring.

Key Features

  • Flexible Pipeline Execution: Execute strategies sequentially for dependent tasks or in parallel for independent, performance-critical operations.
  • Domain-Agnostic Design: Built with generics (IStrategyStep<TContext>) to work with any business domain or data context.
  • Dynamic Scripting: Define and modify business rules at runtime using JavaScript (via Jint) and Lua (via NLua) without recompiling your application.
  • Source Generators: Use the [StrategyStep] attribute on your strategy classes for automatic registration in the .NET dependency injection container.
  • Fluent Builder API: A StrategyBuilder provides a clean, fluent interface for composing ad-hoc workflows and simple strategy sequences.
  • Built-in Monitoring: Enable metrics to automatically track strategy execution counts, duration (min, max, average), success/failure rates, and more.
  • Dependency Injection Friendly: Deep integration with Microsoft.Extensions.DependencyInjection for easy setup and management of strategies.

Installation

Install the main package from NuGet to get started.

dotnet add package FlexibleStrategyFramework

For specific features, you can install the extension packages:

  • FlexibleStrategyFramework.Extensions.DynamicScripting: For JavaScript and Lua support.
  • FlexibleStrategyFramework.Extensions.Monitoring: For performance metrics collection.
  • FlexibleStrategyFramework.SourceGenerators: For automatic strategy registration (used as an analyzer).

Getting Started

Here is a quick guide to setting up and using the framework.

1. Define a Context

Your context class holds the state that is passed through the pipeline. It must implement IContext, but you can inherit from the provided BaseContext for convenience.

// src/FlexibleStrategyFramework.Core/BaseContext.cs
public abstract class BaseContext : IContext
{
    public string ContextId { get; set; } = Guid.NewGuid().ToString();
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    public Dictionary<string, object> Data { get; set; } = new();
    // ...
}

// samples/PaymentProcessor/Contexts/PaymentContext.cs
public class PaymentContext : BaseContext
{
    public string PaymentId { get; set; }
    public decimal Amount { get; set; }
    public string CustomerEmail { get; set; }
    public PaymentStatus Status { get; set; } = PaymentStatus.Pending;
}

2. Create Strategy Steps

A strategy step is a single, atomic piece of work in your pipeline. Mark it with the [StrategyStep] attribute for auto-registration.

// samples/PaymentProcessor/Strategies/PaymentValidationStrategy.cs

using FlexibleStrategyFramework.Abstractions;
using FlexibleStrategyFramework.SourceGenerators; // For StrategyStepAttribute
using PaymentProcessor.Contexts;

[StrategyStep(typeof(PaymentContext), Priority = 100)]
public class PaymentValidationStrategy : IStrategyStep<PaymentContext>
{
    // The generator will use the class name if StepName is not provided.
    public string StepName => "Validation";

    public async Task<StepResult> ExecuteAsync(PaymentContext context)
    {
        Console.WriteLine($"Validating payment {context.PaymentId}...");
        await Task.Delay(100);

        if (context.Amount <= 0)
            return StepResult.Failure("Payment amount must be greater than zero");

        if (string.IsNullOrEmpty(context.CustomerEmail))
            return StepResult.Failure("Customer email is required");

        context.Status = PaymentStatus.Validated;
        return StepResult.Success("Payment validated successfully");
    }
}

3. Configure Services

In your application's startup, add the framework and register your strategies. The source generator automatically finds classes marked with [StrategyStep].

// samples/PaymentProcessor/Program.cs

var services = new ServiceCollection();

// Add logging, etc.
services.AddLogging(builder => builder.AddConsole());

// Add the framework
services.AddFlexibleStrategyFramework(options =>
{
    options.EnableMetrics = true; // Optional: enable monitoring
    options.DefaultTimeout = TimeSpan.FromSeconds(60);
});

// Register strategies (manually or via source generators)
// Manual registration:
services.AddStrategy<PaymentValidationStrategy, PaymentContext>();
services.AddStrategy<FraudDetectionStrategy, PaymentContext>();
services.AddStrategy<GatewayCommunicationStrategy, PaymentContext>();

// Register a use case that will use the pipeline
services.AddScoped<ProcessPaymentUseCase>();

4. Execute the Pipeline

Inject IStrategyPipeline<TContext> into your services and call ExecuteAsync to run the pipeline.

// samples/PaymentProcessor/UseCases/ProcessPaymentUseCase.cs

public class ProcessPaymentUseCase
{
    private readonly IStrategyPipeline<PaymentContext> _pipeline;

    public ProcessPaymentUseCase(IStrategyPipeline<PaymentContext> pipeline)
    {
        _pipeline = pipeline;
    }

    public async Task<PaymentResult> ExecuteAsync(PaymentRequest request)
    {
        var context = new PaymentContext
        {
            Amount = request.Amount,
            CustomerEmail = request.CustomerEmail,
            // ...
        };

        // Execute all registered strategies for PaymentContext
        var pipelineResult = await _pipeline.ExecuteAsync(context);

        if (pipelineResult.IsSuccess)
        {
            Console.WriteLine("Pipeline executed successfully!");
        }
        else
        {
            Console.WriteLine($"Pipeline failed: {string.Join(", ", pipelineResult.Errors)}");
        }
        
        // Map to business result...
        return new PaymentResult { /* ... */ };
    }
}

Advanced Features

Dynamic Scripting (JavaScript & Lua)

Execute business logic from scripts, allowing rules to be changed without redeploying your application.

JavaScript Example

Create a JavaScriptStrategy and pass it your script content. The script can access and modify the context.

// samples/DynamicStrategies/Program.cs
var jsScript = File.ReadAllText("Scripts/discount.js");

var jsStrategy = new JavaScriptStrategy<DynamicStrategyContext>(
    "DiscountCalculation",
    jsScript);

var jsResult = await jsStrategy.ExecuteAsync(jsContext);

discount.js

// samples/DynamicStrategies/Scripts/discount.js
function calculateDiscount(context) {
    var amount = context.Data.amount || 0;
    var customerType = context.Data.customerType || 'regular';
    var discount = 0;

    if (amount > 1000) {
        discount += 0.1; // 10% for large orders
    }

    if (customerType === 'premium') {
        discount += 0.15; // 15% for premium customers
    }
    
    var finalAmount = amount * (1 - discount);

    // The returned object is automatically converted to a StepResult
    return {
        isSuccess: true,
        message: 'Discount calculated successfully',
        outputData: {
            originalAmount: amount,
            discountPercentage: discount * 100,
            finalAmount: finalAmount
        }
    };
}

// Execute the function. The last evaluation is the return value.
calculateDiscount(context);

Strategy Builder

For simpler, ad-hoc workflows, the StrategyBuilder offers a fluent API to chain steps together without needing separate classes for each strategy.

// samples/InvoiceValidator/Program.cs
var builder = new StrategyBuilder<InvoiceValidationContext>(serviceProvider);

var result = await builder
    .AddStep("BasicValidation", async ctx =>
    {
        if (ctx.Amount <= 0)
            return StepResult.Failure("Invoice amount must be positive");
        return StepResult.Success("Basic validation passed");
    })
    .AddStep("AmountCalculation", async ctx =>
    {
        var calculatedTotal = ctx.Lines.Sum(line => line.TotalPrice);
        if (Math.Abs(calculatedTotal - ctx.Amount) > 0.01m)
            return StepResult.Failure("Amount mismatch");
        return StepResult.Success("Amount calculation verified");
    })
    .AddStep<ApplyBusinessRulesStrategy>() // Can mix with existing strategy classes
    .ExecuteAsync(context);

Pipeline Configuration

Customize pipeline execution by passing a PipelineConfiguration object.

// samples/PaymentProcessor/UseCases/ProcessPaymentUseCase.cs
var config = new PipelineConfiguration
{
    // Only execute these specific steps
    RequiredSteps = new List<string> { "Validation", "GatewayProcessing" }, 
    
    // Stop if any step returns a failure
    StopOnFirstFailure = true, 
    
    // Run independent strategies in parallel
    EnableParallelExecution = false,
    
    // Set an overall timeout for the pipeline
    Timeout = TimeSpan.FromSeconds(30), 
};

var pipelineResult = await _pipeline.ExecuteAsync(context, config);

Sample Projects

The repository includes several sample projects to demonstrate various features:

  • PaymentProcessor: A realistic example showing a multi-step payment processing workflow with validation, fraud detection, and gateway communication.
  • ReportGenerator: Demonstrates the difference between sequential and parallel pipeline execution for a report generation task.
  • WorkflowEngine: A complex example that orchestrates a stateful business process, including initialization, validation, approvals, and notifications.
  • DynamicStrategies: A focused sample showcasing how to use JavaScript and Lua to implement dynamic business rules.
  • InvoiceValidator: A simple example using the StrategyBuilder for an ad-hoc validation workflow.

Building from Source

To build the project, run the build script from the root of the repository.

# In PowerShell

# Clean, restore, build, and test
./build.ps1 -Clean -Test

# To also create NuGet packages
./build.ps1 -Pack

The CI build is defined in .github/workflows/ci.yml.

Contributing

Contributions are welcome! Please feel free to open an issue to discuss a bug or feature, or submit a pull request with your improvements.

License

This project is licensed under the MIT License. See the LICENSE file for details.

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 (1)

Showing the top 1 NuGet packages that depend on FlexibleStrategyFramework.Extensions.DynamicScripting:

Package Downloads
FlexibleStrategyFramework

A generic, domain-independent strategy pattern framework for .NET with pipeline support, dynamic scripting, and monitoring

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.0 97 1/5/2026
1.0.1 95 1/5/2026
1.0.0 95 1/5/2026