Round #226

07 May 2026, 15:26· csharp· meta/llama-3.3-70b-instruct· r12-real-contracts
Complexity
band 1
ZP / UO / OBS
13 / 5 / 1
Journey weight
1495
Lightshift ΔL

Prompt

Write a validation pipeline behaviour in MediatR that collects all errors

Zero-point index (what the engine surfaced)

ZPI-ZPI-0019 | 2026-05-07T15:26:30Z Write a validation pipeline behaviour in MediatR that collects all errors ZERO POINT — 13 entries (structural invariants) ● hsl(176.24, 100%, 18%) INotificationHandler<TNotification> [contract] ● hsl(351.03, 100%, 18%) IRequestHandler<TRequest, TResponse> [contract] ● hsl(256.59, 100%, 18%) INotification [contract] ● hsl(276.16, 100%, 18%) IRequest<TResponse> [contract] ● hsl(237.58, 100%, 18%) IPipelineBehavior<TRequest, TResponse> [contract] ● hsl(290.83, 100%, 18%) IRequestPreProcessor<TRequest> [contract] ● hsl(314.89, 100%, 18%) IRequestPostProcessor<TRequest, TResponse> [contract] ● hsl(159.80, 100%, 21%) IValidator<T> [contract] ● hsl(240.67, 100%, 21%) AbstractValidator<T> [contract] ● hsl(175.80, 100%, 21%) IValidatableObject [contract] ● hsl(328.68, 100%, 21%) IValidatorFactory [contract] ● hsl(145.31, 100%, 21%) ValidationResult [contract] ● hsl(39.29, 100%, 21%) ValidationContext<T> [contract] UNOBSERVED — 5 entries (implied truths) ○ hsl(27.69, 100%, 50%) async [feature] ○ hsl(3.75, 100%, 21%) CancellationToken [feature] ○ hsl(31.38, 100%, 40%) Scoped registration [function] ○ hsl(83.08, 100%, 26%) ILogger of T injection [function] ○ hsl(156.92, 100%, 10%) Model state inspection [function] OBSERVED — 1 entries (explicit in request) ◉ hsl(45.00, 100%, 5%) Pipeline behaviour [function] COMPLEXITY │ 19 entries │ spread: 153° │ band: MEDIUM

Baseline response (no ZPI)

**Validation Pipeline Behaviour in MediatR** ============================================= Below is an example of a validation pipeline behaviour in MediatR that collects all errors. ```csharp using MediatR; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; public class ValidationPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse> { private readonly IEnumerable<IValidator<TRequest>> _validators; public ValidationPipelineBehavior(IEnumerable<IValidator<TRequest>> validators) { _validators = validators ?? throw new ArgumentNullException(nameof(validators)); } public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next) { var validationResults = _validators .Select(validator => validator.Validate(request)) .SelectMany(result => result.Errors) .ToList(); if (validationResults.Any()) { throw new ValidationException(validationResults); } return await next(); } } public class ValidationException : Exception { public List<ValidationFailure> Errors { get; } public ValidationException(List<ValidationFailure> errors) { Errors = errors; } } public class ValidationFailure { public string ErrorMessage { get; set; } public string PropertyName { get; set; } } ``` **Using the Validation Pipeline Behaviour** ------------------------------------------ To use the validation pipeline behaviour, you need to register it in the DI container and add the validators for your requests. ```csharp public void ConfigureServices(IServiceCollection services) { services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationPipelineBehavior<,>)); services.AddTransient<IValidator<MyRequest>, MyRequestValidator>(); services.AddMediatR(typeof(Startup)); } public class MyRequestValidator : AbstractValidator<MyRequest> { public MyRequestValidator() { RuleFor(x => x.Name).NotEmpty().WithMessage("Name is required"); RuleFor(x => x.Age).GreaterThan(0).WithMessage("Age must be greater than 0"); } } public class MyRequest : IRequest<MyResponse> { public string Name { get; set; } public int Age { get; set; } } public class MyResponse { public string Message { get; set; } } ``` **Handling Validation Exceptions** --------------------------------- To handle validation exceptions, you can create a middleware that catches the `ValidationException` and returns a response with the validation errors. ```csharp public class ValidationExceptionHandlerMiddleware { private readonly RequestDelegate _next; public ValidationExceptionHandlerMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { try { await _next(context); } catch (ValidationException ex) { context.Response.StatusCode = StatusCodes.Status400BadRequest; await context.Response.WriteAsync(JsonConvert.SerializeObject(new { errors = ex.Errors.Select(e => new { e.ErrorMessage, e.PropertyName }) })); } } } ``` You can add this middleware to the pipeline in the `Startup.cs` file. ```csharp public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // ... app.UseMiddleware<ValidationExceptionHandlerMiddleware>(); // ... } ```

Enhanced response (with ZPI)

```csharp using MediatR; using MediatR.Pipeline; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; public class ValidationPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> { private readonly ILogger<ValidationPipelineBehavior<TRequest, TResponse>> _logger; private readonly IValidatorFactory _validatorFactory; public ValidationPipelineBehavior(ILogger<ValidationPipelineBehavior<TRequest, TResponse>> logger, IValidatorFactory validatorFactory) { _logger = logger; _validatorFactory = validatorFactory; } public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next) { var validator = _validatorFactory.GetValidator(request.GetType()); if (validator != null) { var validationResults = validator.Validate(request); if (!validationResults.IsValid) { var errors = validationResults.Errors.Select(e => new { Property = e.PropertyName, Error = e.ErrorMessage }); _logger.LogError($"Validation failed for {request.GetType().Name}. Errors: {string.Join(", ", errors.Select(e => $"{e.Property}: {e.Error}"))}"); throw new ValidationException(validationResults); } } return await next(); } } public class ValidationException : Exception { public ValidationException(ValidationResult validationResult) { ValidationResult = validationResult; } public ValidationResult ValidationResult { get; } } public class ValidationPipelineBehaviorRegistration { public static void Register(IServiceCollection services) { services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationPipelineBehavior<,>)); } } ``` This implementation provides a validation pipeline behavior for MediatR that collects all errors. It uses the `IValidatorFactory` to get a validator for the request type, and then validates the request using the `Validate` method. If the validation fails, it logs the errors and throws a `ValidationException`. The `ValidationPipelineBehavior` class is registered as a transient service in the `ValidationPipelineBehaviorRegistration` class, which can be used to register the behavior in the DI container. The `ValidationException` class is used to wrap the `ValidationResult` object, which contains the validation errors. This exception can be caught and handled by the application to display the validation errors to the user. Note that this implementation assumes that the request type has a validator registered in the `IValidatorFactory`. If no validator is registered, the behavior will simply pass the request to the next handler in the pipeline.

Grader chain

Each grader reads the same baseline + enhanced pair and casts an independent verdict. Disagreement is the framework's own signal — not noise to be averaged away.

V1claude-haiku-4-5-20251001
Better
V4qwen2.5-coder-7b-instruct
Better

Comments

Our grader said what it said. What do you say? Comment as a guest below.

No comments yet. Be the first to say what you make of this round.

← back to all rounds