diff --git a/readme.md b/readme.md index 2b94343..64b69cf 100644 --- a/readme.md +++ b/readme.md @@ -64,7 +64,7 @@ dotnet new vsa -n - ✅ Using `Postgres` On Top of EfCore - ✅ Using `OpenTelemetry` for collection `logs`, `metrics` and `tracings` - ✅ Using `OpenTelemetry Collector` to receive, process, and export telemetry data to various backends, including Jaeger and Tempo for tracing, Loki and Kibana for logs, and Prometheus for metrics -- ✅ Using `Fluent Validation` and a [Validation Pipeline Behaviour](./src/BuildingBlocks/BuildingBlocks.Validation/RequestValidationBehavior.cs) on top of MediatR +- ✅ Using `Fluent Validation` and a [Validation Pipeline Behaviour](./src/Shared/Validation/README.md) on top of MediatR - ✅ Using different levels of tests like `Unit Tests`, `Integration Tests`, `Contract Test` and `End-To-End Tests` - ✅ Using [Microsoft Tye](https://github.com/dotnet/tye) and `Pm2` for running the application - ✅ Using docker and `docker-compose` for deployment diff --git a/src/Shared/Validation/README.md b/src/Shared/Validation/README.md new file mode 100644 index 0000000..ce9f3ef --- /dev/null +++ b/src/Shared/Validation/README.md @@ -0,0 +1,47 @@ +# Validation Behaviors + +## ✨ Summary +This is FluentValidation + MediatR pipeline integration, cleanly implemented to: + +- Auto-validate requests before handling them + +- Log everything for observability + +- Work with both regular and streaming MediatR requests + +- Keep your handlers minimal and focused (no validation clutter inside handlers) + +## 📦 Context +This folder contains `MediatR` pipeline behaviors for automatic request validation using `FluentValidation`. +They are cross-cutting concerns that run before and after handling a request. +Here, the concern is validation — validating requests automatically before executing handlers. + +## What is it? 🧐 + +These behaviors automatically validate requests before they reach their handlers. This ensures that: + +- Handlers remain clean and focused (no manual validation code) +- Validation logic is centralized and consistent +- Invalid requests short-circuit the pipeline with clear error messages + +## How does it work? + +- If a `FluentValidation` validator exists for a request, it will be invoked automatically. +- If validation passes, the request handler executes normally. +- If validation fails, an exception is thrown (handled globally). + +## Usage + +1. Ensure validators are registered in DI (`FluentValidation`) +2. Register the pipeline behavior in `MediatR` + +```csharp +services.AddScoped(typeof(IPipelineBehavior<,>), typeof(RequestValidationBehavior<,>)); +services.AddScoped(typeof(IStreamPipelineBehavior<,>), typeof(StreamRequestValidationBehavior<,>)); +``` + +## Related +- [FluentValidation](https://docs.fluentvalidation.net/en/latest/) +- [MediatR Pipeline Behaviors](https://github.com/jbogard/MediatR/wiki/Behaviors) +- [Request Validation Behaviour](RequestValidationBehavior.cs) + diff --git a/src/Shared/Validation/RequestValidationBehavior.cs b/src/Shared/Validation/RequestValidationBehavior.cs index 10c727d..d018192 100644 --- a/src/Shared/Validation/RequestValidationBehavior.cs +++ b/src/Shared/Validation/RequestValidationBehavior.cs @@ -7,6 +7,12 @@ namespace Shared.Validation; +/// +/// A MediatR pipeline behavior that automatically validates a request using FluentValidation +/// before invoking its handler. +/// +/// The type of the request message. +/// The type of the response message returned by the handler. public class RequestValidationBehavior( IServiceProvider serviceProvider, ILogger> logger @@ -14,6 +20,14 @@ ILogger> logger where TRequest : IRequest where TResponse : class { + /// + /// Handles the incoming request by validating it (if a validator is registered) + /// and then invoking the next handler in the pipeline. + /// + /// The request message to be handled. + /// A token to observe while waiting for the task to complete. + /// The delegate representing the next step in the pipeline. + /// The response returned by the request handler. public async ValueTask Handle( TRequest message, CancellationToken cancellationToken, @@ -46,6 +60,12 @@ MessageHandlerDelegate next } } +/// +/// A MediatR stream pipeline behavior that automatically validates a streaming request +/// using FluentValidation before yielding responses from its handler. +/// +/// The type of the streaming request message. +/// The type of each response element yielded by the handler. public class StreamRequestValidationBehavior( IServiceProvider serviceProvider, ILogger> logger @@ -58,6 +78,14 @@ ILogger> logger private readonly IServiceProvider _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); + /// + /// Handles the incoming streaming request by validating it (if a validator is registered) + /// and then invoking the next handler in the pipeline to yield responses. + /// + /// The streaming request message to be handled. + /// A token to observe while waiting for the task to complete. + /// The delegate representing the next step in the streaming pipeline. + /// An asynchronous stream of responses yielded by the request handler. public async IAsyncEnumerable Handle( TRequest message, CancellationToken cancellationToken,