Zooper.Bee
3.3.0
dotnet add package Zooper.Bee --version 3.3.0
NuGet\Install-Package Zooper.Bee -Version 3.3.0
<PackageReference Include="Zooper.Bee" Version="3.3.0" />
<PackageVersion Include="Zooper.Bee" Version="3.3.0" />
<PackageReference Include="Zooper.Bee" />
paket add Zooper.Bee --version 3.3.0
#r "nuget: Zooper.Bee, 3.3.0"
#addin nuget:?package=Zooper.Bee&version=3.3.0
#tool nuget:?package=Zooper.Bee&version=3.3.0
Zooper.Bee
<img src="icon.png" alt="Zooper.Bee Logo" width="120" align="right"/>
A flexible and powerful workflow library for .NET that allows you to define complex business processes with a fluent API.
Overview
Zooper.Bee lets you create workflows that process requests and produce either successful results or meaningful errors. The library uses a builder pattern to construct workflows with various execution patterns including sequential, conditional, parallel, and detached operations.
Key Concepts
- Workflow: A sequence of operations that process a request to produce a result or error
- Request: The input data to the workflow
- Payload: Data that passes through and gets modified by workflow activities
- Success: The successful result of the workflow
- Error: The errors result if the workflow fails
Installation
dotnet add package Zooper.Bee
Getting Started
// Define a simple workflow
var workflow = new WorkflowBuilder<Request, Payload, SuccessResult, ErrorResult>(
// Factory function that creates the initial payload from the request
request => new Payload { Data = request.Data },
// Selector function that creates the success result from the final payload
payload => new SuccessResult { ProcessedData = payload.Data }
)
.Validate(request =>
{
// Validate the request
if (string.IsNullOrEmpty(request.Data))
return Option<ErrorResult>.Some(new ErrorResult { Message = "Data is required" });
return Option<ErrorResult>.None;
})
.Do(payload =>
{
// Process the payload
payload.Data = payload.Data.ToUpper();
return Either<ErrorResult, Payload>.FromRight(payload);
})
.Build();
// Execute the workflow
var result = await workflow.Execute(new Request { Data = "hello world" }, CancellationToken.None);
if (result.IsRight)
{
Console.WriteLine($"Success: {result.Right.ProcessedData}"); // Output: Success: HELLO WORLD
}
else
{
Console.WriteLine($"Error: {result.Left.Message}");
}
Building Workflows
Validation
Validates the incoming request before processing begins.
// Asynchronous validation
.Validate(async (request, cancellationToken) =>
{
var isValid = await ValidateAsync(request, cancellationToken);
return isValid ? Option<ErrorResult>.None : Option<ErrorResult>.Some(new ErrorResult());
})
// Synchronous validation
.Validate(request =>
{
var isValid = Validate(request);
return isValid ? Option<ErrorResult>.None : Option<ErrorResult>.Some(new ErrorResult());
})
Guards
Guards allow you to define checks that run before a workflow begins execution. They're ideal for authentication, authorization, account validation, or any other requirement that must be satisfied before a workflow can proceed.
// Asynchronous guard
.Guard(async (request, cancellationToken) =>
{
var isAuthorized = await CheckAuthorizationAsync(request, cancellationToken);
return isAuthorized ? Option<ErrorResult>.None : Option<ErrorResult>.Some(new ErrorResult());
})
// Synchronous guard
.Guard(request =>
{
var isAuthorized = CheckAuthorization(request);
return isAuthorized ? Option<ErrorResult>.None : Option<ErrorResult>.Some(new ErrorResult());
})
Benefits of Guards
- Guards run before creating the workflow context, providing early validation
- They provide a clear separation between "can this workflow run?" and the actual workflow logic
- Common checks like authentication can be standardized and reused
- Failures short-circuit the workflow, preventing unnecessary work
Activities
Activities are the building blocks of a workflow. They process the payload and can produce either a success (with the modified payload) or an error.
// Asynchronous activity
.Do(async (payload, cancellationToken) =>
{
var result = await ProcessAsync(payload, cancellationToken);
return Either<ErrorResult, Payload>.FromRight(result);
})
// Synchronous activity
.Do(payload =>
{
var result = Process(payload);
return Either<ErrorResult, Payload>.FromRight(result);
})
// Multiple activities
.DoAll(
payload => DoFirstThing(payload),
payload => DoSecondThing(payload),
payload => DoThirdThing(payload)
)
Conditional Activities
Activities that only execute if a condition is met.
.DoIf(
payload => payload.ShouldProcess, // Condition
payload =>
{
// Activity that only executes if the condition is true
payload.Data = Process(payload.Data);
return Either<ErrorResult, Payload>.FromRight(payload);
}
)
Groups
Organize related activities into logical groups. Groups can have conditions and always merge their results back to the main workflow.
.Group(
payload => payload.ShouldProcessGroup, // Optional condition
group => group
.Do(payload => FirstActivity(payload))
.Do(payload => SecondActivity(payload))
.Do(payload => ThirdActivity(payload))
)
Contexts with Local State
Create a context with the local state that is accessible to all activities within the context. This helps encapsulate related operations.
.WithContext(
null, // No condition, always execute
payload => new LocalState { Counter = 0 }, // Create local state
context => context
.Do((payload, state) =>
{
state.Counter++;
return (payload, state);
})
.Do((payload, state) =>
{
payload.Result = $"Counted to {state.Counter}";
return (payload, state);
})
)
Parallel Execution
Execute multiple groups of activities in parallel and merge the results.
.Parallel(
null, // No condition, always execute
parallel => parallel
.Group(group => group
.Do(payload => { payload.Result1 = "Result 1"; return payload; })
)
.Group(group => group
.Do(payload => { payload.Result2 = "Result 2"; return payload; })
)
)
Detached Execution
Execute activities in the background without waiting for their completion. Results from detached activities are not merged back into the main workflow.
.Detach(
null, // No condition, always execute
detached => detached
.Do(payload =>
{
// This runs in the background
LogActivity(payload);
return payload;
})
)
Parallel Detached Execution
Execute multiple groups of detached activities in parallel without waiting for completion.
.ParallelDetached(
null, // No condition, always execute
parallelDetached => parallelDetached
.Detached(detached => detached
.Do(payload => { LogActivity1(payload); return payload; })
)
.Detached(detached => detached
.Do(payload => { LogActivity2(payload); return payload; })
)
)
Finally Block
Activities that always execute, even if the workflow fails.
.Finally(payload =>
{
// Cleanup or logging
CleanupResources(payload);
return Either<ErrorResult, Payload>.FromRight(payload);
})
Advanced Patterns
Error Handling
.Do(payload =>
{
try
{
var result = RiskyOperation(payload);
return Either<ErrorResult, Payload>.FromRight(result);
}
catch (Exception ex)
{
return Either<ErrorResult, Payload>.FromLeft(new ErrorResult { Message = ex.Message });
}
})
Conditional Branching
Use conditions to determine which path to take in a workflow.
.Group(
payload => payload.Type == "TypeA",
group => group
.Do(payload => ProcessTypeA(payload))
)
.Group(
payload => payload.Type == "TypeB",
group => group
.Do(payload => ProcessTypeB(payload))
)
Dependency Injection Integration
Zooper.Bee integrates seamlessly with .NET's dependency injection system. You can register all workflow components with a single extension method:
// In Startup.cs or Program.cs
services.AddWorkflows();
This will scan all assemblies and register:
- All workflow validations
- All workflow activities
- All concrete workflow classes (classes ending with "Workflow")
You can also register specific components:
// Register only validations
services.AddWorkflowValidations();
// Register only activities
services.AddWorkflowActivities();
// Specify which assemblies to scan
services.AddWorkflows(new[] { typeof(Program).Assembly });
// Specify service lifetime (Singleton, Scoped, Transient)
services.AddWorkflows(lifetime: ServiceLifetime.Singleton);
Performance Considerations
- Use
Parallel
for CPU-bound operations that can benefit from parallel execution - Use
Detach
for I/O operations that don't affect the main workflow - Be mindful of resource contention in parallel operations
- Consider using
WithContext
to maintain state between related activities
Best Practices
- Keep activities small and focused on a single responsibility
- Use descriptive names for your workflow methods
- Group related activities together
- Handle errors at appropriate levels
- Use
Finally
for cleanup operations - Validate requests early to fail fast
- Use contextual state to avoid passing too many parameters
License
MIT License (Copyright details here)
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. 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 was computed. 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 was computed. 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. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Scrutor (>= 4.2.2)
- Zooper.Fox (>= 1.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Zooper.Bee:
Package | Downloads |
---|---|
Zooper.Bee.MediatR
A .NET library for building robust, functional workflows and processing pipelines. |
GitHub repositories
This package is not used by any popular GitHub repositories.