Hi Amichai! Greetings from Brazil! I am so grateful for your series! I've been following this far and everything just gets better!! Congratulations! Content like this is very rare!
@gabriel.pessoa7 ай бұрын
Brazillian here too! Amichai is helping me so much at my first dev job
@ugochukwuumerie63782 жыл бұрын
Great content 👌 especially the ending part - Yes!. The pipeline behaviours are like class decorators which obeys the "O" in the SOLID principles - the class should be closed for modifications and open for extensions.
@liordagan50982 жыл бұрын
What?! Zero comments about the most beautiful part of this video?! 😍🐶 28:15
@amantinband2 жыл бұрын
Same!
@patrykk.46302 жыл бұрын
Thanks for this video. I was waiting for a good explanation of MediatR behaviors and validating. Can't wait for domain and application validaiton breakthrough :D
@being_aslam_tiger2 жыл бұрын
Thanks for creating awesome stuff. Please keep making videos on c#.
@amantinband2 жыл бұрын
Thanks, Aslam!
@davidpccode Жыл бұрын
Hello great content. Thank you very much. I have read and seen a lot of content about command validation but I still can't find a reason that justifies so much over-engineering and so much complexity. I can achieve the same thing by injecting a class that performs all the validations with less than half the effort and with the same result. what am i missing? Thanks in advance 👍
@pilotboba2 жыл бұрын
So let's go back to when I asked you why your Commands/Queries weren't your API contracts. You stated that you wanted to be able to change the commands/queries implementations without changing the contracts. Ok, fair enough. However, now, you are validating the Command and not the request. So, when you return a validation problem it is possible you are defining a validation problem on a property that doesn't actually exist on the contract. So, your RegisterRequest could have FullName which you map to First Name, Last Name in your command. Your validator finds the Last Name is empty and returns a problem that states, LastName is required or some such error. How is the client supposed to fix this, because he has no LastName property in his contract? Am, I seeing this correctly, or did I miss something?
@amantinband2 жыл бұрын
Great question. You are correct; since we are validating the executing command/query and not the actual request, there can be a mismatch between the two. One of the cons of Application-layer validation (instead of presentation-layer validation) is that we might have already moved from the API request model to the use-case model, and there might be a mismatch. One of the benefits of application layer validation is that you can take into account application logic and include it in your "Bad Request" response. Is it a big deal that the property name in the response's error list doesn't match the request property? I would argue that it usually isn't, but as always, it depends. What do you think?
@pilotboba2 жыл бұрын
@@amantinband I think as a client interacting with an API if I got an error message about a property that wasn't in the request I wouldn't know what to do to fix it or create client-side validations that match the contract. So, in my opinion the Commands and Queries should BE the API contracts. If you need to modify command isn't it a different command, and you should add a new one and maybe deprecate the old one.
@amantinband2 жыл бұрын
On a specific project, maybe. But as a rule of thumb, I would disagree. The API should be known and well documented, and the error response should be descriptive. These together should cover the client’s onboarding to the service. The commands/queries aren't always a 1:1 mapping, and having this abstraction is what the presentation layer is all about. Finished modeling your service and want to switch to gRPC? No problem, you would only update the presentation layer. At Microsoft, there are some services where you have the same flows available for some clients via a REST API and other clients via another technology style bond or gRPC. What do you think? Was that convincing?
@pilotboba2 жыл бұрын
@@amantinband No. I think we are agree about 1 thing, the contracts shouldn't change, but disagree that they should be, or need to be different than the commands and queries. Adding another layer and seem that I don't feel is needed. I guess if you document your error responses it's not too much of an issue, but it just doesn't sit right with me.
@ugursesen76292 жыл бұрын
the tutorials are really great, thanks a lot
@amantinband2 жыл бұрын
Thanks, Ugur!
@Jeroen3001 Жыл бұрын
Instead of invoking a Dynamic Call Site by using the 'dynamic' keyword in '(dynamic)errors' (which is slow) the same effect is accomplished by a simple cast from an object reference: '(TResponse)(object)errors' I try to prevent to use the keyword 'dynamic' at all times when possible.
@m_camper Жыл бұрын
Hi, I'm thinking the same thing and was just about to post a new comment asking if I can do this, but I see I'm not the only one who thinks so 🙂
@m_camper Жыл бұрын
But actually, why another approach is with using reflection but not that simple as in your comment, may be there are some reasons that it will not work?..
@ariefmuhammadlubis18032 жыл бұрын
Finally, I'm very happy and great video
@KarwanEssmat Жыл бұрын
Well Done Amichai, I am excited to fo find your course. it is truly helpful. Actually, I did not use your Error0r library so I had some challenges in returning the exception errors and I used my approach. Thanks for sharing.
@StandleyPeter Жыл бұрын
I really enjoy the series. Have learned a lot from these series. Anyway, alt+z should toggle the words wrap automatically.
@fakeITDevTeam Жыл бұрын
i wish i could be as good as you guys in software development world.
@minhan44446 ай бұрын
Thank you very much about this tutorial :3
@sunnypatel10452 жыл бұрын
Hey dude love your content. Are you going to do a video on testing the api? Love to see your strategy etc.
@amantinband Жыл бұрын
Yup 👍
@arthurfedotiew3609 Жыл бұрын
i don't know if it's just me but that final part with pipeline and Aggregate was so much easier for me when I learned this concept a while ago in js world working with rxjs .pipe(). YOu should probably rename 'pipeline' to 'behavior' when defining Aggregate reducer. Nevertheless, content is terrific as always, thank you Sir!
@TrOgaN_3 ай бұрын
I noticed someting strange, while the validation handler is called, validation errors are returned before it calls the handler. You can even comment out the pipeline definition in the dependency Injection file and it still return validation erroros.
@sunnypatel10452 жыл бұрын
Love your content. It's SO CLEAN :D. Will you demonstrate other behaviors like logging etc?
@amantinband2 жыл бұрын
I might be. Unsure if it would be the simplest way to demonstrate logging, though.
@mahditalebi17702 жыл бұрын
Thanks for the video. It's a little bit hard to read without word wrapping and big font. if you could maybe close the files list or decrease font a little I think it would be much easier to undrestand.
@amantinband2 жыл бұрын
Ooh, interesting feedback. It would be easier for me to code with a smaller font. Do you watch the videos on your phone or computer?
@mahditalebi17702 жыл бұрын
@@amantinband I watch them on my laptop which is 15'.
@nivaldobrasil Жыл бұрын
Thank you.
@novalogic12652 жыл бұрын
Great video as usual. Just one thing, instead dynamic I've implemented in this way: First, I split Command and Query into 2 interfaces public interface ICommand : IRequest { } public class ValidationBehaviour : IPipelineBehavior where TRequest : ICommand { private readonly IEnumerable _validators; public ValidationBehaviour(IEnumerable validators) { _validators = validators; } public async Task Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate next) { if (!_validators.Any()) { return await next(); } var context = new ValidationContext(request); var validationResults = await Task.WhenAll(_validators.Select(v => v.ValidateAsync(context, cancellationToken))); var errors = validationResults.SelectMany(result => result.ToErrors()).ToList(); if (!errors.Any()) { return await next(); } return errors; } } Because, if I need ErrorOr in e.g. some behavior (logging or whatever) after next() to log something with this approach I have an ErrorOr object. What do you think? Also, I dont like dynamic and I dont like exceptions 😉 Edit: result.ToErrors() line ToErrors is an extension😀
@amantinband2 жыл бұрын
And the behavior is invoked? I'll have to check this out if yes
@novalogic12652 жыл бұрын
@@amantinband Yes, behavior is invoked. Here is my request example public class RegisterCommand : ICommand .... So ApiIdentity is TResponse
@amantinband2 жыл бұрын
@NovaLogic Can you hit a breakpoint in the behavior? If yes, will you be able to share a gist? AFAIK this isn't supported yet.
@novalogic12652 жыл бұрын
@@amantinband drive.google.com/drive/folders/1K3-OQBcpEZdufXjukj14xEXJ_2LWvcW-?usp=sharing let me know if you have an access issue
@SzefMann2 жыл бұрын
Great content! What kind of programming books do you recommend?
@amantinband2 жыл бұрын
I rarely read books. Mostly learn from documentation, blogs, and my favorite - existing code bases.
@SzefMann2 жыл бұрын
@@amantinband Pls give examples of existing code bases :D
@amantinband2 жыл бұрын
I spend a lot of time searching within Microsoft's internal code bases. These are the best models of how services (and microservices) scale. Some technologies and architectures also have great examples and templates available on GitHub
@zadidbinazad3655 Жыл бұрын
I have just started to move my API to clean architecture. This helps a lot. Thank you. ❤ Can we have some details about how to work with a SQL database following your approach and how to run CRUD operation in Database?
@SirSpiffzz2 жыл бұрын
Love your videos!
@dennisdurairaj38482 жыл бұрын
Hey Amichai, great content! I've got a question. Doesn't this go against DDD principle of keeping logic(validation in this case) inside entity classes and ValueObjects in the domain? Right now the domain has no knowledge of these validations
@abrahamv092 жыл бұрын
I understand that some validations are going to be repeated in both places, but they are more like insurance. I see it as a way to avoid executing logic that will be invalid due to input parameters. Not all requests will reach the domain layer if you validate the parameters before performing an operation with that layer. Other cases will not even have interaction with the domain, but you will still have to validate input parameters, such as queries. After that, if you somehow make your parameters invalid after the command validators, domain validation will be your insurance. That's how I understand it. Although there are cases where you can ignore the command validators and just use the domain validation, it is up to you.
@msek972 жыл бұрын
Will you cover unit testing of the handlers? I’m curious how do you test it with so implicit validation that is sctually done in runtime behind the scenes. Should we not test invalid inputs then?
@amantinband2 жыл бұрын
Hey Sekresio. Yes, we'll have a couple of videos on testing 👍🏼
@matthewrossee10 ай бұрын
What status code would you assign to Error.Failure? 500? I guess it depends on what I understand by a failure in my system. I think that NotFound, Conflict and Validation solve the 99% of the usecases. So the Failure could mean some unrecoverable error caused by the server, but the one that you expect to happen eventually. But then what about Unexpected? If you ever return Error.Unexpected in your code, it means that you expect something may happen, so it isn’t unexpected. What is your methodology? And big thanks for the amazing erroror library!
@marioteik2 жыл бұрын
I love your content!
@amantinband2 жыл бұрын
Added now, thanks for noticing!
@baulron6 ай бұрын
Thanks!
@amantinband6 ай бұрын
🫶🏼
@alexc.5781 Жыл бұрын
All my sympathies to your enter key
@robertmrobo8954 Жыл бұрын
Do you have an issue with the 'J' button on your keyboard Ami? 😊 Very very very very good videos by the way.
@ayazsohail652Ай бұрын
I changed the validateBehavior from register command to generic type, now validation is not working, API gives no error response.
@gungoromer Жыл бұрын
Teşekkürler.
@amantinband Жыл бұрын
Thanks! 🫶🏼
@androidsavior5 ай бұрын
Can you share the source code of this project ?
@harmony-teams2 жыл бұрын
Great video! Do you use some type of VS Code extension that proposes the code to complete the statement?
@geraldmaale Жыл бұрын
GitHub Copilot
@juankar0085 ай бұрын
github copilot
@foonlam71347 ай бұрын
I am very confused. Why do we need pipeline behaviors? A pipeline behaviour basically does something before the the request is handled and after the request is handled. Why can't we make it just part of the request handler? If it is to implement single responsibility, then why can't we just just call one handler after another in order which does the same thing as the pipeline.
@KLGR1256 ай бұрын
Thats because you want to separate use case handlers from validation. If I understand you correctly, if you create multiple handlers in mediator for every validation you will end up having long chain of mediator invokes in your controller and this chain gonna increase every time you need to add new validation rule. Or you can add your own validator somewhere and invoke it from command handler and this will be single responsibility principle violation. So you want your validation separated both: from command handler and from controller and this what pipeline behavior allows you to do.
@ahmetcanyldz7455 Жыл бұрын
Is it more sensible to configure the life cycle of the fluent validation objets singleton rather than scoped?
@arthurfedotiew3609 Жыл бұрын
Shouldn't you assign null to IValidator? validator at 12.36 when injecting optional validator?
@bookuha Жыл бұрын
Do these commands act like a DTO? Is it appropriate? Should I pass DTO's into them and validate them like that? Doesn't look right for me :c
@mohamedyounesse Жыл бұрын
Can use it in wpf pip behaviors mediatr i thing is distinated for web only asp because i try it many time i given error the services logger cant injected with wpf there are no request
@kennedydre80748 ай бұрын
anyone know how we are connecting the debugger?
@eugene_potashkin2 жыл бұрын
Finally 😃
@omidkianifar51442 жыл бұрын
Thanks for the course. Why u didnt validation on api layer on request models?
@amantinband Жыл бұрын
That's another common approach. I like putting the validation in the application layer rather than the presentation layer.
@omidkianifar5144 Жыл бұрын
@@amantinband this is for performance. In this case what do u prefered? Performance or clean code
@muhammadahsansaifi5182 Жыл бұрын
Oh my God
@vuphancao1224 Жыл бұрын
what is the name extention suggest code in visual code you use ?
@DaminGamerMC2 жыл бұрын
Why the "is 0" thing works
@DeejayWazzouille2 жыл бұрын
Hello, I dont understand the need of this behaviour ? I dont have it and my code still returning the errors as your
@DeejayWazzouille2 жыл бұрын
Nevermind, it's because you validate the command when i validate the request .. :)
@pilotboba2 жыл бұрын
small FYI, this part isn't in the play list. :)
@amantinband2 жыл бұрын
Thanks, added now!
@rmbl3492 жыл бұрын
I love your content but it's really strange for me that you use vs code for this. To be honest without VS + resharper or Rider I feel really unconfortable.
@amantinband2 жыл бұрын
Each one with its pros and cons 🙂
@MilanJovanovicTech2 жыл бұрын
Fix the thumbnail! 😁
@amantinband2 жыл бұрын
Whoops pipline 😂 Thanks 🫶
@MyFuzzyAfterlife2 жыл бұрын
Just some feedback, and this may just be applicable to me. But you go very fast, it's sometimes hard to keep up, and Co-Pilot is not helping with this either. I'm constantly pausing, rewinding, pausing, just to try and keep up. Maybe I'm just slow.
@amantinband2 жыл бұрын
Whoo thats great feedback. I tried going a bit slower in this vodeo, so I'm very curios to hear if others feel the same specifically regarding todays video. Thanks for letting me know!
@ryan-heath2 жыл бұрын
I viewed the vid at 1.5 speed 😅 But then again I’m not particular interested in the little details but more in the overall structure which is good to grasp at 1.5 speed.
@amantinband2 жыл бұрын
Haha I'm a x2 speeder. I sometimes wish I could change real life to x2, but that's an indication I need to work on my patience 😂
@MrDimitri712 жыл бұрын
@@amantinband For me the main problem was the Copilot. A lot of times i couldnt read or associate what the method was doing. A feedback I want to give (Love this series btw) is to spend some time in the beginning explaining what is the structure you are sugesting (Maybe a drawing or something). Implementation details don't matter as much imo, but i really want to absorb HOW it was implemented -structure wise- and WHY, and that was why this video in particular got confusing. But anyways thanks for the informative content.
@saadaldulaijan49572 жыл бұрын
@@amantinband please keep the same speed, people who struggle following you can pause. I love how you making the video short with extensive useful content. Copilot is great 👍