Forgot this line? Your ASP.NET Core app validation might act strange!

I recently encountered a strange issue with ASP.NET Core validation in an inherited codebase. After digging deeper, I realized a simple but crucial step had been missed, causing some pretty frustrating errors. Let me share this information with you so we never encounter this issue again.

The problem

ASP.NET Core loves using data annotations for validation. However, when using FluentValidation, you don’t need or want those built-in validators to interfere with your setup. They can cause redundant checks or conflicts, leading to strange behavior in your app.

The original setup didn’t clear out those default model validators, which is crucial to ensuring FluentValidation works without interference. Whenever a validation error occurred, like passing a null value for the username, the response looked like this:

{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"UserName": [
"The UserName field is required."
]
},
"traceId": "00-54173eba85492e9c17e12babf8c19ed3-f97dca20a4c12b47-00"
}

This error was due to default data annotation validators kicking in. It never even hit the controller during debugging, which made diagnosing the issue tricky.

The fix

The fix is super simple. You just need to add this one line to your service configuration:

services.AddControllers(options =>
{
options.ModelValidatorProviders.Clear(); // Removes all data annotation validation providers
})
.AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<Startup>());

This line basically says, “Hey, ASP.NET Core, thanks for the help, but we’ve got this covered.” It clears out all the data annotation validators, letting FluentValidation handle everything just the way you set it up. After adding this line, validation errors became much more manageable and looked like this from FluentValidation:

{
"type": "Validation",
"title": "ValidationError",
"status": 400,
"detail": "A validation problem occurred.",
"Extension": [
{
"code": "request.UserName",
"message": "UserName field is required."
}
]
}

No more surprises, just smooth sailing.

Conclusion

Don’t skip this step! Adding that line will make your validation life a whole lot easier. Let’s keep things clean and simple together.

As always, here’s to a productive day with warm chai ☕, crunchy biscuits 🍪, and bug-free code 🐞.


Key takeaways

  • Clear ASP.NET Core’s default model validators with options.ModelValidatorProviders.Clear() when using FluentValidation to prevent conflicts
  • Without this line, data annotation validators can interfere with your FluentValidation setup and produce unexpected validation errors
  • FluentValidation rules are more flexible and maintainable than scattered data annotations across your models
  • The fix is one line, but the debugging time it saves is enormous when validation behaves unexpectedly
  • Always test your validation pipeline early to catch these integration issues before they reach production

Happy Coding! 🎉