Open janschmidmaier50 opened 1 year ago
IValidator
does not expose ValidateAsync
.
IValidator
does not exposeValidateAsync
.
Please read #30
In addition, I think it could be better to use DI to get the FluentValidation.IValidator
If we have specific rules based on action (insert, update, etc) or other property, we can use the When(...) feature or RuleSets.
For unit testing, when you want to test a business case from the BL, you have to provide a fully valid entity event if the case only needs some properties. You lose the advantage of AutoFixture as soon as you have to specify a valid value for several properties.
In addition, the unit test is not testing a single unit of the app anymore because it tests Business and Validation at the same time. Specially when the validation is running complexe rules which read data for example.
In addition to arguments above, the use of ValidationResult type allows us to use the extension method for unit testing (https://docs.fluentvalidation.net/en/latest/testing.html)
In addition, I think it could be better to use DI to get the FluentValidation.IValidator in BLs instead of giving it the responsibility to create concrete validators.
Seconded. This has been documented and will be discussed in the "Business Layer New Model" meeting.
There is now the FluentValidation in place, which makes things easier.
Keep on reading, the surprise is down there ;)
Place of implementation
First of all the class
ValidationBase<>
and the corresponding interfaceIValidator
should be part of the Arc4u framework and not be generated for each project. Why is that ? Imho there is no need to adjust the implementation ofValidationBase<>
and even if so, this can be done within the project itself. Furthermore right now there will be multiple occurrences of the exact same code within one solution, because it will be generated for every single backend service. This is senseless code duplication, which should actually be found by code inspection. Right now, when using the guidance for Visual Studio 2019 aValidationBase
(non generic) was created. So if one now creates a new business object with the guidance 2022 a Validator will be created inheriting the not existingValidationBase<>
and using the not available FluentValidation. If this would have been implemented within the Arc4u, it would have been obvious and the oldValidationBase
could have been marked obsolete, giving the team time to adjust their code.ValidationBase<>
implementationThe
ValidationBase<>
must not keep track of the object to validate, as well as the messages. Doing so makes the instantiation of the class harder, the calling not threadsafe. Furthermore the code is not idempotent, because runningValidate()
one time will manipulate themessage
object differently then running it a couple of times. It is also not obvious that callingValidate()
will change the provided (by ctor)Messages
object, which violates the CleanCode principle and makes theValidate()
method unpure and dishonest. So instead ofit might be
making the method pure, because there is no dependency anymore and the input objects are not modified anymore. So the provided objects can now be immutable. This also makes the validation threadsafe. Downside is now, that we need to provide the
ignoreWarnings
flag, because we can not read it from the provided messages, which the validation itself should not bother with. A possible improvement follows in the next chapter.Messages vs ValidationResult
Up until now, we are always using
Messages
to handle results of the validation. Since we are using FluentValidation now, we might not need that anymore. We can now even separate things by their concern, so that there is a service for everything that needs to be done, likeSo why don't we write extension methods for that ?
(this is just a code snippet, on how things could be done!)
Having that, we could change the
ValidationBase<>
like thatConclusion
This way neither the
ValidationBase<>
nor theMessages
(including theMessage
) is needed anymore - at least concerning the validation.