Hi Milan, thanks for sharing. My two cents: Command validation pertain to the Behavioural layer of the application and should be costrained to that layer. Assumed your stack, the best and elegant approach is to implement an CommandValidationBehaviour into the Mediatr pipeline. This middleware would throw a CommandValidationException that can be further processed by the upstream layers, presentation in particular. MOREOVER, and this is the point, you can also (and SHOULD) implement a (synchronous and "singletoned") validation at Request layer. This latter validation layer is to guard from malformed user request (aka 404): stateless, light, focused on syntax rather then semantics, and very performant (the "why" of singleton). while the former, is to protect from business violation rules (aka 401, 400 and so on…): deeper and semanthics reach. A bit of duplication may arise but in complex application, where you reuse commands in multiple use cases, this design is very scalable. The point to recognize is that validation is a topic that you should address at every layer of your onion… Thanks for your time
I agree, and I already have a video about implementing the Validation pipeline behavior. How would the request validation be implemented? What's your approach?
I know... I am pedantic, but I am trying to understand and your videos are a gold mine. That said, why put the validation in the application layer? It seems that email uniqueness is a business rule, so validation must occur in the domain layer. Am i missing something? Thanks for your patience Milan.
I think in the Persistance 'CustomerConfiguration' he already assigned it to be unique, so duplicates can never happen; to be honest I don't like the idea of giving the model on creation a repository and then do a 'check', if it already exists (from performance perspective also), but I did like the idea to enforce everything. I don't think a repository belongs in a model, anyways because there are probably ways to get DI working in there.
@@pilotboba I hope the above comment will not be banned for containing two links. If it is so, please tell me so I can provide information about where to find the resources without providing the direct URL.
should we use fluentvalidation for the domain layer? in this case it is used as an "application rule" right? How do we differentiate business rules and application rules?
Buena sugerencia : Seria los mismo que una API comun de streeming Task UploadFile() con var file = Request.Form.Files[0];. Luego Internamente en la capa de Infra un FTPWrapper que lo envie al FTP server. (Obtions-> previouslyconfigurated. not harcoded ajjaja )
how to export the metadata of entity validation rules into Json for front end. The problem I am trying to solve here, when our client side is SPA (Angular/React) we have to write same validation logic twice in back end and also in front end. I wan't to create a unified validation both back end & front end. So that I only write validation rules once. For example I wan't to export rules in following format : { "Name": { "NotEmpty": true, "MinLength": 3, "MaxLength": 200 } ... .... }
Hi Milan, thanks for your amazing videos I learn a lot from them. I do have a question regarding of how Can keep my service class clean and elegant when I need to implement more than 1 validators in the constructor?
How do you handle concurrency? Is it possible to receive two requests using the same email at the same time without being aware of the other attempt to save a customer with that email?
@@gonzalorf Sure, there should be used another approach - insert email into a table with unique email column index, and also insert customer/user in one transaction.
The idea to check uniqueness before an attempt to store new email into the database is dangerous. Either you should lock entire table on reading or you should catch a key violation exception on writing.
Its very helpful to follow your videos. I see here many are bugging you with wanting some ideal code in the video. I see that I can build application together with you and learn and improve knowledge. So once again, great and very helpful approach in videos content, the plan on what you publish with compromise and refactoring in later videos. Thx. a lot. And by the way you have call to repo by passing email where name should be passed in comand handler class. Just wanted to brag that I'm closely watching and implementing your examples 😉
It's funny how everyone expects me to implement a complete production ready application in a 10-min video, and I only want to focus on something specific while disregarding everything else. As long as people like you can see the value, that's all I care about. Yeah, the double Email in the constructor pissed me off but I didn't want to re-record to fix it 😅
@@MilanJovanovicTech We wouldn't be able to learn and apply new knowledge if you put all at once by omitting showing parts of the code and cutting explanations. Gradual approach is the only way for us who do not know everything already, or we just don't need to play smart. I use to watch your video one day, then implement it myself next day by checking the video while developing. This works for me. I suppose this is why you get so many new followers. First thing that I thought was the same. He must be crazy about rerecording that trivial typo 😁 Wish you all the best!
И вообще, что это за подход - проверять уникальность email перед вставкой юзера ? Нужно иметь уникальный ключ в БД по email, попробовать вставить в транзакции, и затем добавлять юзера, а если такой email уже есть, то все откатить - хотя email просто частный случай, а более общий - валидация на уровне БД, вставляем, не получается по уникальному индексу, откатываем что сделали до этого. Т.е. в нагруженных системах, между проверкой уникальности и вставкой проходит время, хоть и миллисекунды, но это надо учитывать - и единственный вариант, индекс, транзакции - это если еще что-то связанное вставляем.
@@MilanJovanovicTech Верно. Но сам подход должен быть пессимистичным, и все должно быть решено на уровне БД, а не клиента БД. С email, оптимистичный подход может сработать, и за 10 лет никогда в такую ошибку можно не попасть, даже в высоконагруженных системах, но в других случаях это невалидно, и если уж взялись учить, то учите правильно.
What the benefit of validate the command in the API rather than in the handler ? If we use the same handler in 2 differents route, we'll duplicate the code ? (maybe too specific case ?) Anyway, thanks for sharing this !
Да ну нафиг, как-то сложно для простой валидации. ЗЫ. Работал на одном проекте, и там то-же все было сделано на командах/запросах, причем еще и в генериках, ужас - чтобы разобраться в коде, приходилось искать имплементацию за 3 шага, место одного, а там таких было тысячи. В итоге проект пришлось спасть, т.к. при разрастании он стал неподдерживаемым (not-maintainable). Есть-же принцип KISS - ну зачем усложнять на ровном месте ???
@@MilanJovanovicTech Понятно, что это пример как можно сделать проекту плохо - завести кучу всяких интерфейсов, абстракций, которая в будущем, казалось бы, может что-то принести, а по факту все очень усложняет - разработчики вынуждены исследовать код, скакать по реализациям интерфейсов и т.д. Хотя, чего проще, просто проверить email в сервисе юзеров при его добавлении ? KISS - Keep it simple s****d
Hi, Just curious on how you guys use these db checks without hints that try to lock the table...for instance, with the default transaction level for sql server, how can you ensure that 2 parallel requests won't end up duplicating the records with the same email?
Can't you add the command validator to the createcustomercommandhandler instead of the controller/route? That it stays together and will be explicit? That can either be together in that file or as DI. Thanks for the video :-)
Commands don't return a value, so didn't want to bother with implementing a flow for that. It was easier to just place it in the endpoint to illustrate the point
Yoo Milan! It's either you're too fast or I'm too slow "compiling" what you are writing there. Adjust your mediator brooo, allow the stupid me to catch up 😢
man I am new to the channel and every time I watch a video I feel like a stupid potato cuz u r always using things u already built and I just don't know where to start like what is the Error class what is a pipeline behavior I feel so lost.
Here's the Result class: gist.github.com/m-jovanovic/aa25b1ae424c985ff8ae696a79b6fe6e But try to focus on the concepts, the implementation details can change
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
Even if i won't watch it immediately I must enter, just to smash that like button for our good friend Milan. Hvala ti brate!
Haha, thanks a lot, brate! 😁
Hi Milan, thanks for sharing.
My two cents: Command validation pertain to the Behavioural layer of the application and should be costrained to that layer.
Assumed your stack, the best and elegant approach is to implement an CommandValidationBehaviour into the Mediatr pipeline.
This middleware would throw a CommandValidationException that can be further processed by the upstream layers, presentation in particular.
MOREOVER, and this is the point, you can also (and SHOULD) implement a (synchronous and "singletoned") validation at Request layer.
This latter validation layer is to guard from malformed user request (aka 404): stateless, light, focused on syntax rather then semantics, and very performant (the "why" of singleton).
while the former, is to protect from business violation rules (aka 401, 400 and so on…): deeper and semanthics reach.
A bit of duplication may arise but in complex application, where you reuse commands in multiple use cases, this design is very scalable.
The point to recognize is that validation is a topic that you should address at every layer of your onion…
Thanks for your time
I agree, and I already have a video about implementing the Validation pipeline behavior.
How would the request validation be implemented? What's your approach?
I was just about to write that you should index database calls that you use in validator, but then you showed the ef configuraiton. Nice work :)
I already knew what a few people were going to say 😁
Would be nice to have these rules in the domain layer, to really encapsulate the domain logic where it belongs
How would you do it?
I know... I am pedantic, but I am trying to understand and your videos are a gold mine. That said, why put the validation in the application layer? It seems that email uniqueness is a business rule, so validation must occur in the domain layer. Am i missing something?
Thanks for your patience Milan.
I think in the Persistance 'CustomerConfiguration' he already assigned it to be unique, so duplicates can never happen; to be honest I don't like the idea of giving the model on creation a repository and then do a 'check', if it already exists (from performance perspective also), but I did like the idea to enforce everything.
I don't think a repository belongs in a model, anyways because there are probably ways to get DI working in there.
So you want to inject persistence into your domain layer?
If not, how would you enforce this in the domain?
Not sure I like those dragons.
@@pilotboba I hope the above comment will not be banned for containing two links. If it is so, please tell me so I can provide information about where to find the resources without providing the direct URL.
It's the everlasting debate of domain purity vs completeness vs performance
You can't have all three.
great video milan ! for my projects, i use the pipeline behavior with mediatr to doesn't have redundancy in my handle method :).
Yeah, I already have a video about that
should we use fluentvalidation for the domain layer? in this case it is used as an "application rule" right? How do we differentiate business rules and application rules?
Very good question, but shouldn't domain layer be referencesless?
Buena sugerencia : Seria los mismo que una API comun de streeming Task UploadFile() con var file = Request.Form.Files[0];. Luego Internamente en la capa de Infra un FTPWrapper que lo envie al FTP server. (Obtions-> previouslyconfigurated. not harcoded ajjaja )
Application is also part of the Core (where Domain also is) so it's one and the same
You are just like MS Docs. Assuming that everyone is an expert already and just writing code without explaination.
Yes, I assume that my audience has some prior experience
how to export the metadata of entity validation rules into Json for front end.
The problem I am trying to solve here, when our client side is SPA (Angular/React) we have to write same validation logic twice in back end and also in front end.
I wan't to create a unified validation both back end & front end. So that I only write validation rules once.
For example I wan't to export rules in following format :
{
"Name": {
"NotEmpty": true,
"MinLength": 3,
"MaxLength": 200
}
...
....
}
I don't see much value in that... You'll write it twice (once...) and forget about it
Hi Milan, thanks for your amazing videos I learn a lot from them. I do have a question regarding of how Can keep my service class clean and elegant when I need to implement more than 1 validators in the constructor?
You can inject IEnumerable and validate all of them - but at that point you're better off using some sort of middleware
CreateCommand validations are almost the same for UpdateCommand validations, how to handle that?
Write them twice 🤷♂️
How do you handle concurrency? Is it possible to receive two requests using the same email at the same time without being aware of the other attempt to save a customer with that email?
I didn't see the part where you set an index. Thank you.
@@gonzalorf Sure, there should be used another approach - insert email into a table with unique email column index, and also insert customer/user in one transaction.
The idea to check uniqueness before an attempt to store new email into the database is dangerous. Either you should lock entire table on reading or you should catch a key violation exception on writing.
Unique constraint at the DB
Then you do not need to check if an email exists, just insert it, and catch key violation, first call is not needed.
Its very helpful to follow your videos. I see here many are bugging you with wanting some ideal code in the video. I see that I can build application together with you and learn and improve knowledge. So once again, great and very helpful approach in videos content, the plan on what you publish with compromise and refactoring in later videos. Thx. a lot. And by the way you have call to repo by passing email where name should be passed in comand handler class. Just wanted to brag that I'm closely watching and implementing your examples 😉
It's funny how everyone expects me to implement a complete production ready application in a 10-min video, and I only want to focus on something specific while disregarding everything else. As long as people like you can see the value, that's all I care about.
Yeah, the double Email in the constructor pissed me off but I didn't want to re-record to fix it 😅
@@MilanJovanovicTech We wouldn't be able to learn and apply new knowledge if you put all at once by omitting showing parts of the code and cutting explanations. Gradual approach is the only way for us who do not know everything already, or we just don't need to play smart. I use to watch your video one day, then implement it myself next day by checking the video while developing. This works for me. I suppose this is why you get so many new followers.
First thing that I thought was the same. He must be crazy about rerecording that trivial typo 😁 Wish you all the best!
keep up the great content
Will do!
И вообще, что это за подход - проверять уникальность email перед вставкой юзера ? Нужно иметь уникальный ключ в БД по email, попробовать вставить в транзакции, и затем добавлять юзера, а если такой email уже есть, то все откатить - хотя email просто частный случай, а более общий - валидация на уровне БД, вставляем, не получается по уникальному индексу, откатываем что сделали до этого. Т.е. в нагруженных системах, между проверкой уникальности и вставкой проходит время, хоть и миллисекунды, но это надо учитывать - и единственный вариант, индекс, транзакции - это если еще что-то связанное вставляем.
Или блокировка всей таблицы с момента чтения до момента записи нового email. Что в высоконагруженной системе невозможно.
Pessimistic vs optimistic approach
@@MilanJovanovicTech Верно. Но сам подход должен быть пессимистичным, и все должно быть решено на уровне БД, а не клиента БД.
С email, оптимистичный подход может сработать, и за 10 лет никогда в такую ошибку можно не попасть, даже в высоконагруженных системах, но в других случаях это невалидно, и если уж взялись учить, то учите правильно.
thanks buddy. Good stuff right here.
Appreciate it!
Isn't it breaking dependency indirection? I mean you define concrete implementation of validation right in application layer. Or is it a compromise?
A compromise of sorts, just showcasing what's possible
why Add Customer Method Not Async ?
Doesn't need to be 🤔
@@MilanJovanovicTech Explain to me why please
Why do you not use a Pipeline Behavior to add a validation layer before the handler. I think that with that the handler will be much cleaner
HE commented about that at the very end of the video.
Just an example + I already have a video about that
Hi Milan, I would like to know what is the theme you use in Visual Studio and if you plan to publish a course in the future?
VS dark theme + R# syntax highlighting
What the benefit of validate the command in the API rather than in the handler ?
If we use the same handler in 2 differents route, we'll duplicate the code ? (maybe too specific case ?)
Anyway, thanks for sharing this !
Just an example, you can place it in a pipeline behavior
how can we validate with more than one parameter?
can u show me sample code for that
Just write each validation separately
Can u Teach File Uploader Service With Ftp Type in Cqrs pattern ?
Unlikely
How to pass multilingual message in fluent validation without .resx approach. I have list of language specific error messages stored in database.
Not sure, what do the docs say?
Да ну нафиг, как-то сложно для простой валидации.
ЗЫ. Работал на одном проекте, и там то-же все было сделано на командах/запросах, причем еще и в генериках, ужас - чтобы разобраться в коде, приходилось искать имплементацию за 3 шага, место одного, а там таких было тысячи. В итоге проект пришлось спасть, т.к. при разрастании он стал неподдерживаемым (not-maintainable). Есть-же принцип KISS - ну зачем усложнять на ровном месте ???
Just an example of using async validation with FluentValidation, doesn't have to be how you do it
@@MilanJovanovicTech Понятно, что это пример как можно сделать проекту плохо - завести кучу всяких интерфейсов, абстракций, которая в будущем, казалось бы, может что-то принести, а по факту все очень усложняет - разработчики вынуждены исследовать код, скакать по реализациям интерфейсов и т.д. Хотя, чего проще, просто проверить email в сервисе юзеров при его добавлении ? KISS - Keep it simple s****d
Hi,
Just curious on how you guys use these db checks without hints that try to lock the table...for instance, with the default transaction level for sql server, how can you ensure that 2 parallel requests won't end up duplicating the records with the same email?
There's a unique index on the DB level, only one of them can insert the record
@@MilanJovanovicTech if that is the case, what's the purpose of the db check in code?
It's just slowing down your app, no?
How would you convert Fluent Validation errors to ProblemDetails object?
This + a global exception handler: www.milanjovanovic.tech/blog/cqrs-validation-with-mediatr-pipeline-and-fluentvalidation
Can't you add the command validator to the createcustomercommandhandler instead of the controller/route? That it stays together and will be explicit? That can either be together in that file or as DI.
Thanks for the video :-)
Commands don't return a value, so didn't want to bother with implementing a flow for that. It was easier to just place it in the endpoint to illustrate the point
If its a business rule, why isn't it on domain layer?
How would you enforce it in the Domain layer?
Thx
No problem!
Yoo Milan! It's either you're too fast or I'm too slow "compiling" what you are writing there. Adjust your mediator brooo, allow the stupid me to catch up 😢
Yeah, I kind of assume people have some idea of what I'm talking about. I'm not really "beginner" friendly
12:30 What extension/setttings do you use to show all the current values to the right of your code?
No idea to be honest, could be R#
Are you from Croatia? 🙂
Serbia
man I am new to the channel and every time I watch a video I feel like a stupid potato cuz u r always using things u already built and I just don't know where to start like what is the Error class what is a pipeline behavior I feel so lost.
Here's the Result class: gist.github.com/m-jovanovic/aa25b1ae424c985ff8ae696a79b6fe6e
But try to focus on the concepts, the implementation details can change
You explain things way too fast and jumping from on one thing to another, I would like you to slow down a bit and explain things properly
I generally expect viewers to be somewhat familiar with the topics. Unless it's a beginner video - and this one isn't
@@MilanJovanovicTech fair enough
*pink glove*