SagaFlow 0.1.14

dotnet add package SagaFlow --version 0.1.14
NuGet\Install-Package SagaFlow -Version 0.1.14
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="SagaFlow" Version="0.1.14" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add SagaFlow --version 0.1.14
#r "nuget: SagaFlow, 0.1.14"
#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.
// Install SagaFlow as a Cake Addin
#addin nuget:?package=SagaFlow&version=0.1.14

// Install SagaFlow as a Cake Tool
#tool nuget:?package=SagaFlow&version=0.1.14

SagaFlow

A framework to quickly scaffold an application based on a declarative message DTO format. Define your messages (commands and/or events) as POCO DTOs, and have a fully functional UI and underlying queue/workflow engine automatically built to handle the messages. You write message classes, plus your business logic within handlers and/or sagas - everything else is generated at runtime.

Message-based Design

The design has been inspired by ServiceStack. Rather than repeat the benefits of a message based design here, please read up on the great docs over at ServiceStack. eg:

Getting Started

SagaFlow heavily relies on Rebus under the covers to facilate the messaging and saga/workflow engine. It is worth familiarizing yourself with Rebus and service buses in general.

Define your messages

For example, a command to add a new tenant to your infrastructure:

public record AddTenantCommand
{
	public string? Name { get; init; }
}
Scheduled re-occuring commands

For commands that are executed on a scheduled time.

Using the CommandAttribute, add SagaFlow.Interfaces package to the class library containing your messages. Decorate the message with the CommandAttribute with a cron expression for when the job should run.

[Command("Take a shower", Cron = "30 17 * * * *")] // Takes a shower 5:30 pm everyday 
public record TakeAShower { }

If you don't want to use the SagaFlow.Interfaces package, then you can specify the cron expression as part of the DisplayNameAttribute. This allows you to keep your messages library decoupled from SagaFlow.

[DisplayName("Take a shower [cron: 30 17 * * * *]")] // Takes a shower 5:30 pm everyday 
public record TakeAShower { }

Implement your logic

Application logic is written inside of message handlers. These are facilitated directly via Rebus - read up more here.

public class AddTenantCommandHandler : IHandleMessages<AddTenantCommand>
{
    public Task Handle(AddTenantCommand command)
    {
        var db = ...;
        return db.Tenants.Add(new Tenant { Name = command.Name });
    }
}

Resource lists

As well as executing commands, an application almost always needs to display back some lists of resources (often with further commands possible per resource). To achieve this within SagaFlow, implement a resource provider:

public class TenantProvider : IResourceListProvider<Tenant>
{
    public Task<IList<Tenant>> GetAll()
    {
        var db = ...;
        return db.Tenants;
    }
}

public class Tenant
{
    public Guid Id { get; init; }
    public string Name { get; init; }
}

Register middleware

SagaFlow relies on installing its own middleware to publish your app schema, serve the UI, serve your app's resources and receive messages. Firstly configure your providers, handlers and the core SagaFlow service (and underlying Rebus service bus):

builder.Services.AddScoped<IResourceListProvider<Tenant>>(s => new TenantProvider());
builder.Services.AddScoped<AddTenantCommandHandler>();
builder.Services.AddSagaFlow(o => o
    .AddResourceProvidersFromAssemblyOf<TenantProvider>()
    .AddCommandsOfType<AddTenantCommand>()
    .WithLogging(l => l.Console())
    .WithTransport(t => t.UsePostgreSql(db, "messages", "ops-panel.workflow"))
    .WithSubscriptionStorage(s => s.StoreInPostgres(db, "subscriptions", isCentralized: true))
    .WithSagaStorage(s => s.StoreInPostgres(db, "saga-data", "saga-index"))
    .WithRouting(r => r.TypeBased().MapAssemblyOf<AddTenantCommand>("ops-panel"))
    );

Run your app

Your app will serve the generated SagaFlow UI under todo... Insert screenshot of above UI here

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.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
0.1.14 79 5/22/2024
0.1.13 87 5/17/2024