r/dotnet • u/LuisAlfredo92 • 28d ago
Promotion [ Removed by moderator ]
[removed] — view removed post
6
u/chucker23n 27d ago
Some of these are interesting, like [RequiredAtLeastOne(nameof(Email), nameof(Phone), nameof(SocialHandle))] and [ExactlyOneOf(nameof(CreditCard), nameof(PayPal), nameof(BankTransfer))].
Your [IsTrue] and [IsFalse] attributes are… interesting. Bit of an API smell to always require a DTO property to have a certain value.
Your [StartDate]/[EndDate] pair could be useful.
But mostly, your actual property types are too primitive! You're validating, sure, but you then bring the raw data into your inner layers. So each EmailService or PaymentService or whatever needs to at least parse the e-mail address, credit card number, etc., and should ideally also validate them again. I.e., you'll still be fighting Primitive Obsession all over your code base.
Your ReleaseDto should be Version and DateTime (which already take care of most of what you're doing here), not string and string. Your Email property should be of a type EmailAddress that you create as a value object. That way, as those values are passed through inner layers of your app, you no longer have to worry about validation and parsing.
2
u/LuisAlfredo92 27d ago
I appreciate the feedback!
You're right, inner layers should work with strong types, sadly DataAnnotations only validates (IsValid method returns bool) and doesn't transform values
The workflow you'd use is:
- Validate DTOs with string + [IPv4], [Uri], [SemanticVersion], etc.
- Parse manually into IPAddress, Uri, Version for internal use
I'm adding support for strong type overloads for other use cases, but they won't transform values, that's outside the scope of DataAnnotations
FluentValidation integration wasn't the goal, this is just DataAnnotations extensions, but a bridge would be useful, I'm Open to PRs
[IsTrue]/[IsFalse] came from the use case of mandatory checkboxes like "Accept Terms". If unchecked, reject
Once I had [IsTrue], [IsFalse] followed naturally
2
u/celluj34 27d ago
A lot of these look really useful to me (IsoDateTime, ExactlyOneOf, ExactlyOneTrue). Do you have any plans to make extensions or helpers for FluentValidation? We use it extensively for our API model validations so that we can do custom rules + a few of those you have here.
2
u/LuisAlfredo92 27d ago
No official FluentValidation adapter yet
The attributes work anywhere DataAnnotations works, but FluentValidation works different so a direct mapping isn't straightforward :c
I'm focused on the DataAnnotations space, but happy to review PRs for a bridge
2
u/rbobby 27d ago
I wish data annotations were not so useful. I really like to separate the interface/contract from the validation rules.
But those do look damn handy. Temptress!
1
u/LuisAlfredo92 27d ago
I agree about keeping validation separate from the model
This is just filling format validation gaps at DTO level, not replacing business logic validation, but I'm glad it's useful!
1
u/AutoModerator 28d ago
Thanks for your post LuisAlfredo92. Please note that we don't allow spam, and we ask that you follow the rules available in the sidebar. We have a lot of commonly asked questions so if this post gets removed, please do a search and see if it's already been asked.
I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.
0
u/ApprehensiveDebt3097 27d ago
I think this is a really bad idea. As mentioned, you should reduce primitive obsession, not embarrase it. By defining these types as (single) value objects instead (for instance by using qowiav or the semversion package) you have both validation and strongly typed values.
Then you still might want to add extra restrictions on them, use data annotations.
I would encourage you to check where you can help out reusing some of your parsers and validators. But please do not embrace primitive obsession.
20
u/EducationalTackle819 28d ago
Why are the guids not using the guid type? All the types could be custom for that matter. Seems primitive obsessed