question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Discussion: FluentValidation breaking changes going forward

See original GitHub issue

For FluentValidation 10, I’m considering making several breaking changes that I feel will help the library continue to evolve, but I’m not sure whether these changes are necessarily worth it. Over the last 10 years I’ve tried to avoid major breaking changes as FluentValidation has a large user-base, and also breaking changes tend to generate a large number of support requests. As the only developer on this project (which I do in my free time), support requests can be a huge time-sink.

I’d really appreciate others’ opinions of whether this is a worthwhile effort, particularly those who have been involved in similar efforts in other OSS projects. At the moment there are 3 main areas I’m considering which will introduce breaking changes: Generics in the internal model, changes asynchronous validation, and dropping support for older .NET versions.

Generics in the Internal Model.

FluentValidation’s public API (the fluent interface) is strongly-typed with generics. This public API builds an internal model, which does not use generics, and uses object instances to represent both the root model being validated, as well as the individual property values. This decision was originally made to allow the internal API to be a lot more malleable, and be able to customize/extend behaviour which isn’t necessarily type-safe at compiletime (but would be at runtime).

An example of this is transformations which allow the type of the property for while the rule is defined to be changed to another type.

I would like to change this to use generics all the way through FluentValidation, which will eliminate boxing and provide much more type-safety throughout. The main areas that need changing are PropertyRule and PropertyValidator (and all their subclasses).

PropertyRule represents a rule, and is instantiated whenever you call RuleFor. This would be changed to PropertyRule<T>, and would receive a ValidationContext<T> during its Validate methods. I don’t think there are many people this would affect (although I could be wrong). Instantiating a Rule class directly isn’t something that would be done outside of the library (with hindsight, this should not have ever been a public class but back when I started the project I thought it was better that as much as possible was public/virtual. Unfortunately this makes it hard to change the internal model without affecting end users)

As well as the internal model, there are a couple of parts of the public API that would be affected. For years, the way to make a reusable property validator was to create a class that inherits from PropertyValidator (docs). This would require anyone using this approach to inherit from a new PropertyValidator<T, TProperty> instead. Anyone accessing the InstanceToValidate or PropertyValue properties on PropertyValidatorContext would also need to change to using PropertyValidatorContext<T, TProperty> instead.

The fluent interface would also receive an additional type-parameter, representing the current property validator that is active in the chain. This would affect custom extension methods that add to the fluent interface (which is a popular way of extending the library). For example, the WithMessage method in the library currently looks like this:

public static IRuleBuilderOptions<T, TProperty> WithMessage<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, string errorMessage) {
	return rule.Configure(config => {
			config.CurrentValidator.Options.SetErrorMessage(errorMessage);
	});
}

…but would instead become something like the following (note the extra generic)

public static IRuleBuilderOptions<T, TProperty, TValidator> WithMessage<T, TProperty, TValidator>(this IRuleBuilderOptions<T, TProperty, TValidator> rule, string errorMessage) {
	return rule.Configure((rule, currentValidator) => {
		currentValidator.SetErrorMessage(errorMessage);
	});
}

This would affect anyone who has built extension methods on top of IRuleBuilder<T,TProperty>

Asynchronous changes

Covered by https://github.com/FluentValidation/FluentValidation/issues/1481. At the moment it’s too easy to accidentally force async rules to be run synchronously. This change would introduce a separate base class for validators (AsyncAbstractValidator). Async property validators (such as MustAsync) and async conditions (WhenAsync/UnlessAsync) would only be available in validators that inherit from this class.

Classes that inherit from the new AsyncAbstractValidator would not be automatically invoked during the ASP.NET MVC/WebApi validation process (as they don’t support async rules).

This is again a big breaking change.

Supporting older .net versions

The main FluentValidation library currently supports netstandard2, meaning it runs on net461 and newer. I’d particularly like to drop support for .NET 4.x, as it’s becoming a pain to support, but I’m not sure what percentage of the FluentValidation userbase is still running on .net 4.x.

I’d also like to make some of the newer c# features (particularly default interface methods, which would make building the fluent interface easier) but these are locked to .net core 3.1 and newer. .net core 2.1 doesn’t reach EOL until late next 2021.

The first 2 of these are a huge amount of work to implement, so I’m hesitating whether or not they’re worth it, and would appreciate others’ feedback.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:2
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
oskardudyczcommented, Sep 19, 2020

Yup, for your case that it sounds reasonable to wait with dropping the support for .NET Core 2.1. However, you may also try to publish the desired roadmap - with few months of notice about dropping support (eg. till the end of the year). During that time you may try to get the feedback from users. In the worst case, you’ll just prolong it till August.

Again, they can use the version as they are (you may provide some bug fixes to release branches), but new features will be only available in netstandard 2.1 and netcoreapp 3.1.

1reaction
oskardudyczcommented, Sep 19, 2020

@JeremySkinner

Yes, I was thinking that the next version would still allow async property validators validators to be used inside the non-async AbstractValidator, but would be marked as obsolete. In the subsequent version that would then be removed entirely, giving a grace period where people can migrate.

That looks like the right way 👍

I agree, which is why I dropped support for non-LTS .net core versions with FV 9. Unfortunately .net 4.x is still supported as long as windows is 😭

I assume that it’s fine to restrict support to .NET Standard 2.1 for the regular package. The issue is with ASP.NET packages?

Maybe you could gather from NuGet statistic of how many users are using .NET versions that you don’t want to support? If it appears that there are a lot of them then you could release the last version supporting those versions and inform that from the next version there won’t be official support for them but only per-case paid support (so similar as MS does with .NET and Oracle with Java). Thoughts?

Read more comments on GitHub >

github_iconTop Results From Across the Web

10.0 Upgrade Guide — FluentValidation documentation
FluentValidation 10.0 is a major release that included several breaking changes. Please review this document carefully before upgrading from ...
Read more >
Built-In, Nested, Custom Validators with FluentValidation
In this article we are going to learn more about different Validators with FluentValidation, that we can use to protect our app from...
Read more >
Using Fluent Validation in ASP.NET Core
In this article, we will talk about Fluent Validation and its implementation in ASP.NET Core Applications. We will discuss the preferred alternative to...
Read more >
Using FluentValidation in ASP.NET Web API for Model ...
aspdotnetcore #dotnet6 # fluentvalidation API Model validation using ... That opens up a way to reuse model validation across HTTP-based as ...
Read more >
.NET 5 Breaking Changes for ASP.NET Core - InfoQ
NET 5 Breaking Changes series, we look at ASP.NET Core. ... Moving forward, the Http version is the officially sanctioned class.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found