Search code examples
c#.net-5fluentvalidation

How to validate requests with FluentValdation instead of data annotations?


I created a new .Net 5 Web API with the following setup

public class MyController : ControllerBase
{
    [HttpGet("{Title}")]
    public ActionResult<string> Get([FromRoute] RouteModel routeModel)
    {
        return Ok(routeModel);
    }
}

public class RouteModel
{
    [MinLength(3)]
    public string Title { get; set; }
}

The request validation works fine. Since I'm using FluentValidation I installed the package

FluentValidation.AspNetCore v10.3.0

and updated the Startup.ConfigureServices method to

public void ConfigureServices(IServiceCollection services)
{
    services.AddValidatorsFromAssemblies(AppDomain.CurrentDomain.GetAssemblies());
    services.AddControllers();
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApplication", Version = "v1" });
    });
}

Instead of using the data annotations I removed the data annotations from RouteModel.Title and created this validator

public class RouteModelValidator : AbstractValidator<RouteModel>
{
    public RouteModelValidator()
    {
        RuleFor(model => model.Title).MinimumLength(3);
    }
}

I would expect a ValidationException and this would result into a 500 status code if the title has a length less than 3. But it seems there is no validation trigger anymore, the request always passes.

Does someone know what's missing?


Solution

    1. Register FluentValidation as

      services
        .AddFluentValidation(x => x.RegisterValidatorsFromAssemblies(AppDomain.CurrentDomain.GetAssemblies()));
      
    2. Mark your Controller with ApiController attribute

      [ApiController]
      public class MyController : ControllerBase
      

    Otherwise, you should manually validate ModelState, something like:

    [HttpGet("{Title}")]
    public ActionResult<string> Get([FromRoute] RouteModel routeModel)
    {
       if (!ModelState.IsValid)
       {
          return BadRequest("bad");
       }
       return Ok(routeModel);
    }
    

    Some info:

    It depends on the type of controller - if you're using the [ApiController] attribute, then ASP.NET will generate a Bad Request result automatically. If you don't use the ApiController attribute (ie for non-api controllers, such as where you return a view), then you're expected to handle the ModelState.IsValid check manually (see the asp.net doc link above). But again, this is a convention of ASP.NET, it isn't a feature of FluentValidation.