diff --git a/.github/workflows/nuget.publish.yml b/.github/workflows/nuget.publish.yml index 8b4ae8b..844f1d7 100644 --- a/.github/workflows/nuget.publish.yml +++ b/.github/workflows/nuget.publish.yml @@ -86,6 +86,7 @@ jobs: matrix: project: - Zooper.Bee/Zooper.Bee.csproj + - Zooper.Bee.MediatR/Zooper.Bee.MediatR.csproj steps: - name: Checkout Repository diff --git a/CHANGELOG.md b/CHANGELOG.md index 34ec761..b0887bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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` 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 @@ -20,11 +30,11 @@ 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 @@ -32,8 +42,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### 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 @@ -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 diff --git a/Directory.Build.props b/Directory.Build.props index 30684bf..0445d1e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -13,7 +13,7 @@ A .NET library for building robust, functional workflows and processing pipelines. - 3.1.0 + 3.2.0 true diff --git a/Zooper.Bee.MediatR/WorkflowHandler.cs b/Zooper.Bee.MediatR/WorkflowHandler.cs new file mode 100644 index 0000000..7ca2835 --- /dev/null +++ b/Zooper.Bee.MediatR/WorkflowHandler.cs @@ -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; + +/// +/// Base class for workflow handlers that process requests through MediatR +/// +/// The request type +/// The internal workflow payload type +/// The success result type +/// The error result type +public abstract class WorkflowHandler + : IRequestHandler> + where TRequest : IRequest> +{ + /// + /// Gets the factory function to create the initial payload from the request. + /// + protected abstract Func PayloadFactory { get; } + + /// + /// Gets the selector function to create the success result from the final payload. + /// + protected abstract Func ResultSelector { get; } + + /// + /// Configures the workflow using the provided builder. + /// + /// The workflow builder to configure + protected abstract void ConfigureWorkflow(WorkflowBuilder builder); + + /// + /// Handles the request and returns the result. + /// + /// The request to handle + /// The cancellation token + /// Either an error or success result + public async Task> Handle( + TRequest request, + CancellationToken cancellationToken) + { + var workflow = CreateWorkflow(); + return await workflow.Execute(request, cancellationToken); + } + + /// + /// Creates the workflow instance. + /// + /// The configured workflow + // ReSharper disable once MemberCanBePrivate.Global + protected Workflow CreateWorkflow() + { + var builder = new WorkflowBuilder( + PayloadFactory, + ResultSelector + ); + + ConfigureWorkflow(builder); + + return builder.Build(); + } +} \ No newline at end of file diff --git a/Zooper.Bee.MediatR/Zooper.Bee.MediatR.csproj b/Zooper.Bee.MediatR/Zooper.Bee.MediatR.csproj new file mode 100644 index 0000000..3dbbffb --- /dev/null +++ b/Zooper.Bee.MediatR/Zooper.Bee.MediatR.csproj @@ -0,0 +1,16 @@ + + + + netstandard2.0 + + + + + + + + + + + + diff --git a/Zooper.Bee.sln b/Zooper.Bee.sln index 9286a67..34be02f 100644 --- a/Zooper.Bee.sln +++ b/Zooper.Bee.sln @@ -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 @@ -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 diff --git a/Zooper.Bee/Zooper.Bee.csproj b/Zooper.Bee/Zooper.Bee.csproj index e9993c9..a39f6f1 100644 --- a/Zooper.Bee/Zooper.Bee.csproj +++ b/Zooper.Bee/Zooper.Bee.csproj @@ -9,7 +9,6 @@ -