> This project was originally initiated by [Powered Software Inc.](https://poweredsoft.com/) and was forked from the [PoweredSoft.CQRS](https://github.com/PoweredSoft/CQRS) Repository # CQRS Our implementation of query and command responsibility segregation (CQRS). ## Getting Started > Install nuget package to your awesome project. | Package Name | NuGet | NuGet Install | |-----------------------------------------| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |-----------------------------------------------------------------------:| | Svrnty.CQRS | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS/) | ```dotnet add package Svrnty.CQRS ``` | | Svrnty.CQRS.MinimalApi | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.MinimalApi.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.MinimalApi/) | ```dotnet add package Svrnty.CQRS.MinimalApi ``` | | Svrnty.CQRS.FluentValidation | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.FluentValidation.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.FluentValidation/) | ```dotnet add package Svrnty.CQRS.FluentValidation ``` | | Svrnty.CQRS.DynamicQuery | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.DynamicQuery.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.DynamicQuery/) | ```dotnet add package Svrnty.CQRS.DynamicQuery ``` | | Svrnty.CQRS.DynamicQuery.MinimalApi | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.DynamicQuery.MinimalApi.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.DynamicQuery.MinimalApi/) | ```dotnet add package Svrnty.CQRS.DynamicQuery.MinimalApi ``` | | Svrnty.CQRS.Grpc | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.Grpc.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.Grpc/) | ```dotnet add package Svrnty.CQRS.Grpc ``` | | Svrnty.CQRS.Grpc.Generators | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.Grpc.Generators.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.Grpc.Generators/) | ```dotnet add package Svrnty.CQRS.Grpc.Generators ``` | > Abstractions Packages. | Package Name | NuGet | NuGet Install | | ---------------------------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -----------------------------------------------------: | | Svrnty.CQRS.Abstractions | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.Abstractions.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.Abstractions/) | ```dotnet add package Svrnty.CQRS.Abstractions ``` | | Svrnty.CQRS.DynamicQuery.Abstractions | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.DynamicQuery.Abstractions.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.DynamicQuery.Abstractions/) | ```dotnet add package Svrnty.CQRS.DynamicQuery.Abstractions ``` | | Svrnty.CQRS.Grpc.Abstractions | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.Grpc.Abstractions.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.Grpc.Abstractions/) | ```dotnet add package Svrnty.CQRS.Grpc.Abstractions ``` | ## Sample of startup code for gRPC (Recommended) ```csharp using Svrnty.CQRS; using Svrnty.CQRS.FluentValidation; using Svrnty.CQRS.Grpc; var builder = WebApplication.CreateBuilder(args); // Register your commands with validators builder.Services.AddCommand(); builder.Services.AddCommand(); // Register your queries builder.Services.AddQuery(); // Configure CQRS with gRPC support builder.Services.AddSvrntyCqrs(cqrs => { // Enable gRPC endpoints with reflection cqrs.AddGrpc(grpc => { grpc.EnableReflection(); }); }); var app = builder.Build(); // Map all configured CQRS endpoints app.UseSvrntyCqrs(); app.Run(); ``` ### Important: gRPC Requirements The gRPC implementation uses **Grpc.Tools** with `.proto` files and **source generators** for automatic service implementation: #### 1. Install required packages: ```bash dotnet add package Grpc.AspNetCore dotnet add package Grpc.AspNetCore.Server.Reflection dotnet add package Grpc.StatusProto # For Rich Error Model validation ``` #### 2. Add the source generator as an analyzer: ```bash dotnet add package Svrnty.CQRS.Grpc.Generators ``` The source generator is automatically configured as an analyzer when installed via NuGet and will generate both the `.proto` files and gRPC service implementations at compile time. #### 3. Define your C# commands and queries: ```csharp public record AddUserCommand { public required string Name { get; init; } public required string Email { get; init; } public int Age { get; init; } } public record RemoveUserCommand { public int UserId { get; init; } } ``` **Notes:** - The source generator automatically creates: - `.proto` files in the `Protos/` directory from your C# commands and queries - `CommandServiceImpl` and `QueryServiceImpl` implementations - FluentValidation is automatically integrated with **Google Rich Error Model** for structured validation errors - Validation errors return `google.rpc.Status` with `BadRequest` containing `FieldViolations` - Use `record` types for commands/queries (immutable, value-based equality, more concise) - No need for protobuf-net attributes - just define your C# types ## Sample of startup code for Minimal API (HTTP) For HTTP scenarios (web browsers, public APIs), you can use the Minimal API approach: ```csharp using Svrnty.CQRS; using Svrnty.CQRS.FluentValidation; using Svrnty.CQRS.MinimalApi; var builder = WebApplication.CreateBuilder(args); // Register your commands with validators builder.Services.AddCommand(); builder.Services.AddCommand(); // Register your queries builder.Services.AddQuery, PersonQueryHandler>(); // Configure CQRS with Minimal API support builder.Services.AddSvrntyCqrs(cqrs => { // Enable Minimal API endpoints cqrs.AddMinimalApi(); }); // Add Swagger (optional) builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } // Map all configured CQRS endpoints (automatically creates POST /api/command/* and POST/GET /api/query/*) app.UseSvrntyCqrs(); app.Run(); ``` **Notes:** - FluentValidation is automatically integrated with **RFC 7807 Problem Details** for structured validation errors - Use `record` types for commands/queries (immutable, value-based equality, more concise) - Supports both POST and GET (for queries) endpoints - Automatically generates Swagger/OpenAPI documentation ## Sample enabling both gRPC and HTTP You can enable both gRPC and traditional HTTP endpoints simultaneously, allowing clients to choose their preferred protocol: ```csharp using Svrnty.CQRS; using Svrnty.CQRS.FluentValidation; using Svrnty.CQRS.Grpc; using Svrnty.CQRS.MinimalApi; var builder = WebApplication.CreateBuilder(args); // Register your commands with validators builder.Services.AddCommand(); builder.Services.AddCommand(); // Register your queries builder.Services.AddQuery(); // Configure CQRS with both gRPC and Minimal API support builder.Services.AddSvrntyCqrs(cqrs => { // Enable gRPC endpoints with reflection cqrs.AddGrpc(grpc => { grpc.EnableReflection(); }); // Enable Minimal API endpoints cqrs.AddMinimalApi(); }); // Add HTTP support with Swagger builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } // Map all configured CQRS endpoints (both gRPC and HTTP) app.UseSvrntyCqrs(); app.Run(); ``` **Benefits:** - Single codebase supports multiple protocols - gRPC for high-performance, low-latency scenarios (microservices, internal APIs) - HTTP for web browsers, legacy clients, and public APIs - Same commands, queries, and validation logic for both protocols - Swagger UI available for HTTP endpoints, gRPC reflection for gRPC clients # Fluent Validation FluentValidation is optional but recommended for command and query validation. The `Svrnty.CQRS.FluentValidation` package provides extension methods to simplify validator registration. ## With Svrnty.CQRS.FluentValidation (Recommended) The package exposes extension method overloads that accept the validator as a generic parameter: ```bash dotnet add package Svrnty.CQRS.FluentValidation ``` ```csharp using Svrnty.CQRS.FluentValidation; // Extension methods for validator registration // Command with result - validator as last generic parameter builder.Services.AddCommand(); // Command without result - validator included in generics builder.Services.AddCommand(); ``` **Benefits:** - **Single line registration** - Handler and validator registered together - **Type safety** - Compiler ensures validator matches command type - **Less boilerplate** - No need for separate `AddTransient>()` calls - **Cleaner code** - Clear intent that validation is part of command pipeline ## Without Svrnty.CQRS.FluentValidation If you prefer not to use the FluentValidation package, you need to register commands and validators separately: ```csharp using FluentValidation; using Svrnty.CQRS; // Register command handler builder.Services.AddCommand(); // Manually register validator builder.Services.AddTransient, EchoCommandValidator>(); ``` # 2024-2025 Roadmap | Task | Description | Status | |----------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|--------| | Support .NET 8 | Ensure compatibility with .NET 8. | ✅ | | Support .NET 10 | Upgrade to .NET 10 with C# 14 language support. | ✅ | | Update FluentValidation | Upgrade FluentValidation to version 11.x for .NET 10 compatibility. | ✅ | | Add gRPC Support with source generators | Implement gRPC endpoints with source generators and Google Rich Error Model for validation. | ✅ | | Create a demo project (Svrnty.CQRS.Grpc.Sample) | Develop a comprehensive demo project showcasing gRPC and HTTP endpoints. | ✅ | | Create a website for the Framework | Develop a website to host comprehensive documentation for the framework. | ⬜️ |