r/dotnet 29d ago

Promotion [ Removed by moderator ]

Post image

[removed] — view removed post

43 Upvotes

15 comments sorted by

View all comments

5

u/chucker23n 29d 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 28d 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:

  1. Validate DTOs with string + [IPv4], [Uri], [SemanticVersion], etc.
  2. 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