Problem with implementing FluentValidation with Clean Architecture

59 Views Asked by At

I recently started making new app using Clean Architecture + CQRS with MediatR. This is my first attempt to this architecture and I want to implement this architecture without using any templates, because I want to understand how it works. Currently I am trying to implement FluentValidation to my app but one think that I know for sure is that it is not working :(

My github repo for broader view https://github.com/szymonJag/Chatter_v1

I am trying to follow Milan Jovanovic tutorials from YT. (https://www.youtube.com/watch?v=85dxwd8HzEk&t)

So I created ValidationBehavior class in my Application Project exactly like it looks in tutorial.

public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken) { if (!validators.Any()) { return await next(); }
    Error[] errors = validators
        .Select(validator => validator.Validate(request))
        .SelectMany(validationResult => validationResult.Errors)
        .Where(validationFailure => validationFailure is not null)
        .Select(failure => new Error(failure.PropertyName, failure.ErrorMessage))
        .Distinct().ToArray();
    if (errors.Any())
    {
        return CreateValidationResult<TResponse>(errors);
    }
    return await next();
}
private static TResult CreateValidationResult<TResult>(Error[] errors) where TResult : Result
{
    if (typeof(TResult) == typeof(Result))
    {
        return (ValidationResult.WithErrors(errors) as TResult)!;
    }
    object validationResult = typeof(ValidationResult<>)
        .GetGenericTypeDefinition()
        .MakeGenericType(typeof(TResult).GenericTypeArguments[0])
        .GetMethod(nameof(ValidationResult.WithErrors))!
        .Invoke(null, new object?[] { errors })!;

    return (TResult)validationResult;
}

Then I have CreateTodoCommand and CreateTodoCommandValidator

public sealed record class CreateTodoCommand(string Title, string Description, PriorityLevel Priority) : ICommand<Guid>{}

 internal class CreateTodoCommandValidator : AbstractValidator<CreateTodoCommand>
 {
     public CreateTodoCommandValidator()
     {
         RuleFor(x => x.Title).NotEmpty().MinimumLength(2);
         RuleFor(x => x.Description).NotEmpty();
         RuleFor(x => x.Priority).NotEmpty();
     }
 }

My problem is that the validation is not working when I am trying to create todo and todo is added to database. When I am debbuging my app, debugger is not even reaching Handle method from ValidationBehavior. Below how I am injecting behavior in Application

public static class DependencyInjection
{
    public static Assembly Assembly { get; set; } = typeof(DependencyInjection).Assembly;
    public static IServiceCollection AddApplication(this IServiceCollection services)
    {
        services.AddAutoMapper(Assembly.GetExecutingAssembly());
        services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly(), includeInternalTypes: true);
        services.AddMediatR(cfg =>
        {
            cfg.RegisterServicesFromAssembly(Assembly);
            cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
        });
        return services;
    }
}

Then in Program.cs

builder.Services.AddApplication();
0

There are 0 best solutions below