Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/nuget.publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ jobs:
matrix:
project:
- Zooper.Bee/Zooper.Bee.csproj
- Zooper.Bee.MediatR/Zooper.Bee.MediatR.csproj

steps:
- name: Checkout Repository
Expand Down
50 changes: 31 additions & 19 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,22 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 3.2.0 - 2025-04-24

### Added

- New project `Zooper.Bee.MediatR` for MediatR integration
- New `WorkflowHandler<TRequest, TPayload, TSuccess, TError>` base class for defining workflows as MediatR handlers
- Support for creating dedicated workflow classes that integrate with MediatR's request/response pattern

## [3.1.0] - 2025-04-23

### Added

- Added new extension methods for dependency injection:
- `AddWorkflows()` - Registers all workflow components (validations, activities, and workflows)
- `AddWorkflowValidations()` - Registers workflow validations only
- `AddWorkflowActivities()` - Registers workflow activities only
- `AddWorkflows()` - Registers all workflow components (validations, activities, and workflows)
- `AddWorkflowValidations()` - Registers workflow validations only
- `AddWorkflowActivities()` - Registers workflow activities only

- Added support for automatic assembly scanning to discover workflow components
- Added the ability to specify service lifetime for workflow registrations
Expand All @@ -20,20 +30,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Complete redesign of the workflow feature API
- New `Group` method that groups activities with an optional condition
- New `WithContext` method for isolated contexts with their own local state
- New `Detach` method for executing activities without merging their results back
- New `Parallel` method for parallel execution of multiple groups
- New `ParallelDetached` method for parallel execution of detached activities
- New `Group` method that groups activities with an optional condition
- New `WithContext` method for isolated contexts with their own local state
- New `Detach` method for executing activities without merging their results back
- New `Parallel` method for parallel execution of multiple groups
- New `ParallelDetached` method for parallel execution of detached activities
- Better support for nullable conditions - all new methods accept nullable condition
- Clear separation of merged and non-merged execution paths
- Improved naming consistency across the API

### Changed

- **BREAKING CHANGE**: Reorganized internal class structure
- Added feature-specific namespaces and folders
- Created a consistent `IWorkflowFeature` interface for all features
- Added feature-specific namespaces and folders
- Created a consistent `IWorkflowFeature` interface for all features
- **BREAKING CHANGE**: Renamed `Branch` to `Group` for better clarity
- **BREAKING CHANGE**: Renamed `BranchWithLocalPayload` to `WithContext` to better express intention

Expand Down Expand Up @@ -74,35 +84,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Added unconditional branch with local payload method overload
- New `BranchWithLocalPayload` method that doesn't require a condition parameter and always executes
- Supports both callback-style API and fluent API patterns: `.BranchWithLocalPayload(localPayloadFactory, branch => { ... })`
- New `BranchWithLocalPayload` method that doesn't require a condition parameter and always executes
- Supports both callback-style API and fluent API patterns:
`.BranchWithLocalPayload(localPayloadFactory, branch => { ... })`

## [2.1.0] - 2025-04-21

### Added

- Added support for branches with isolated local payloads
- New `BranchWithLocalPayload` method that allows branches to use their own payload type
- Activities within these branches can access and modify both the main payload and the local payload
- Local payloads are isolated to their branch and don't affect other parts of the workflow
- New `BranchWithLocalPayload` method that allows branches to use their own payload type
- Activities within these branches can access and modify both the main payload and the local payload
- Local payloads are isolated to their branch and don't affect other parts of the workflow

## [2.0.0] - 2025-04-19

### Added

- Added an improved API for workflow branching that doesn't require `.EndBranch()` calls
- New `Branch` method overload that accepts a configuration action: `.Branch(condition, branchBuilder => { ... })`
- New `Branch` method overload without a condition for logical grouping of activities: `.Branch(branchBuilder => { ... })`
- New `Branch` method overload that accepts a configuration action: `.Branch(condition, branchBuilder => { ... })`
- New `Branch` method overload without a condition for logical grouping of activities:
`.Branch(branchBuilder => { ... })`

### Changed

- **BREAKING CHANGE**: Fixed XML documentation warnings in `WorkflowBuilder`
- Removed unnecessary param tags from class-level documentation
- Removed unnecessary param tags from class-level documentation

### Deprecated

- The `.EndBranch()` method in `BranchBuilder` is now considered deprecated and will be removed in a future version
- Use the new callback-style API for defining branches instead
- Use the new callback-style API for defining branches instead

### Compatibility

Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<Description>A .NET library for building robust, functional workflows and processing pipelines.</Description>

<!-- Version information -->
<Version>3.1.0</Version>
<Version>3.2.0</Version>

<!-- Source linking -->
<PublishRepositoryUrl>true</PublishRepositoryUrl>
Expand Down
68 changes: 68 additions & 0 deletions Zooper.Bee.MediatR/WorkflowHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using MediatR;
using Zooper.Fox;

// ReSharper disable IdentifierTypo

namespace Zooper.Bee.MediatR;

/// <summary>
/// Base class for workflow handlers that process requests through MediatR
/// </summary>
/// <typeparam name="TRequest">The request type</typeparam>
/// <typeparam name="TPayload">The internal workflow payload type</typeparam>
/// <typeparam name="TSuccess">The success result type</typeparam>
/// <typeparam name="TError">The error result type</typeparam>
public abstract class WorkflowHandler<TRequest, TPayload, TSuccess, TError>
: IRequestHandler<TRequest, Either<TError, TSuccess>>
where TRequest : IRequest<Either<TError, TSuccess>>
{
/// <summary>
/// Gets the factory function to create the initial payload from the request.
/// </summary>
protected abstract Func<TRequest, TPayload> PayloadFactory { get; }

/// <summary>
/// Gets the selector function to create the success result from the final payload.
/// </summary>
protected abstract Func<TPayload, TSuccess> ResultSelector { get; }

/// <summary>
/// Configures the workflow using the provided builder.
/// </summary>
/// <param name="builder">The workflow builder to configure</param>
protected abstract void ConfigureWorkflow(WorkflowBuilder<TRequest, TPayload, TSuccess, TError> builder);

/// <summary>
/// Handles the request and returns the result.
/// </summary>
/// <param name="request">The request to handle</param>
/// <param name="cancellationToken">The cancellation token</param>
/// <returns>Either an error or success result</returns>
public async Task<Either<TError, TSuccess>> Handle(
TRequest request,
CancellationToken cancellationToken)
{
var workflow = CreateWorkflow();
return await workflow.Execute(request, cancellationToken);
}

/// <summary>
/// Creates the workflow instance.
/// </summary>
/// <returns>The configured workflow</returns>
// ReSharper disable once MemberCanBePrivate.Global
protected Workflow<TRequest, TSuccess, TError> CreateWorkflow()
{
var builder = new WorkflowBuilder<TRequest, TPayload, TSuccess, TError>(
PayloadFactory,
ResultSelector
);

ConfigureWorkflow(builder);

return builder.Build();
}
}
16 changes: 16 additions & 0 deletions Zooper.Bee.MediatR/Zooper.Bee.MediatR.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MediatR" Version="12.0.1" />
<PackageReference Include="Zooper.Fox" Version="1.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Zooper.Bee\Zooper.Bee.csproj" />
</ItemGroup>

</Project>
6 changes: 6 additions & 0 deletions Zooper.Bee.sln
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Zooper.Bee.Example", "Zoope
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Zooper.Bee.Tests", "Zooper.Bee.Tests\Zooper.Bee.Tests.csproj", "{3AC893B3-275D-44C6-ACCD-1A0B2A3D0A7C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Zooper.Bee.MediatR", "Zooper.Bee.MediatR\Zooper.Bee.MediatR.csproj", "{7EA02FFD-720F-4B3D-A5A7-368E88AB36B8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -24,5 +26,9 @@ Global
{3AC893B3-275D-44C6-ACCD-1A0B2A3D0A7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3AC893B3-275D-44C6-ACCD-1A0B2A3D0A7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3AC893B3-275D-44C6-ACCD-1A0B2A3D0A7C}.Release|Any CPU.Build.0 = Release|Any CPU
{7EA02FFD-720F-4B3D-A5A7-368E88AB36B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7EA02FFD-720F-4B3D-A5A7-368E88AB36B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7EA02FFD-720F-4B3D-A5A7-368E88AB36B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7EA02FFD-720F-4B3D-A5A7-368E88AB36B8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
1 change: 0 additions & 1 deletion Zooper.Bee/Zooper.Bee.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MediatR" Version="12.5.0" />
<PackageReference Include="Scrutor" Version="4.2.2" />
<PackageReference Include="Zooper.Fox" Version="1.0.0" />
</ItemGroup>
Expand Down