Cleaning up Your Validation Code in .NET

Поділитися
Вставка
  • Опубліковано 6 вер 2024
  • Check out my courses: dometrain.com
    Become a Patreon and get source code access: / nickchapsas
    Hello, everybody, I'm Nick, and in this video, I will show you how you can clean up your validation code in .NET by using MediatR's Pipeline Behavior feature but also PreProcessors.
    Workshops: dometrain.com/...
    Don't forget to comment, like and subscribe :)
    Social Media:
    Follow me on GitHub: bit.ly/ChapsasG...
    Follow me on Twitter: bit.ly/ChapsasT...
    Connect on LinkedIn: bit.ly/ChapsasL...
    Keep coding merch: keepcoding.shop
    #csharp #dotnet

КОМЕНТАРІ • 117

  • @nickchapsas
    @nickchapsas  Рік тому +9

    Use code LAUNCH at dometrain.com for a 15% OFF discount on any course. Also, what do you think about the website?

    • @user-yj5gr6wc9e
      @user-yj5gr6wc9e Рік тому +1

      Something that is slightly annoying when watching a video in full screen, at least on mobile, and then it goes to the next chapter it shows the video in the smaller player. When you are holding your phone horizontally its kind of annoying to have to keep pressing the full screen button every few minutes.

    • @leonardoformaggi7614
      @leonardoformaggi7614 Рік тому

      Honestly I didn't like to click on a course, go to another page, click to buy it, go to another page, and then discover the price, already in a checkout page.

    • @ivan07z583
      @ivan07z583 Рік тому

      @@user-yj5gr6wc9e It's not only on mobile, it happens on desktop too, but I think he didn't build the webpage from zero, I think it uses an external service, so I'm not sure if it's something he can change. I agree it's really annoying to be losing the full-screen mode every time that a video finishes

    • @nickchapsas
      @nickchapsas  Рік тому +1

      @@leonardoformaggi7614 The price is on the course page, you don't need to click to buy it to see the price.

    • @leonardoformaggi7614
      @leonardoformaggi7614 Рік тому

      ​@@nickchapsas I can see no prices. I'd provide a screenshot if I could. Both on mobile and computer, the only way for me to see the prices is buying the course.

  • @stryke0151
    @stryke0151 Рік тому +38

    I've tried Mediatr in several projects now but I've reversed them all back to a simple ICommandHandler with TCommand, and IF I need to validate for instance I just put that single line in.
    In the end it just feels like you are moving code off to DI/Mediatr, making it hard to see what a command actually will do once its being fired off. Plus relying on third party libraries for "basic" needs.
    You still have to register each validator so bottom line nothing really changes in terms of "repeatability", you sacrifice readability for it. And what if "validation" is also checking something in the database? Now you validate the validity of your command partly in a validator but database state wise you still need to check conditions inside your handler or do you really want to start adding more logic than basic property validations?
    I feel that mediatr is a library which hides possible complexity in your application a lot and makes it easier to just keep on piling on pre-processors for those couple of commands that need em. And often very "basic" needs that would just be a couple of lines for the handlers that really need them. Sure the simple, basic first examples seem like a good enough idea, but I feel it gets complicated and very opaque pretty fast.
    It would be interesting to see what the performance impact on this is as well, especially when you have commands that dont need validation/etc but still goes through all the preprocessing loops vs just calling it when you need it.

    • @yegorandrosov6334
      @yegorandrosov6334 Рік тому +2

      @@tcortega pls

    • @CesarDemi81
      @CesarDemi81 Рік тому +2

      You not knowing how to correctly implement it doesn't mean is wrong.
      For example, you don't need to register every single validator because with a little reflection or something like Scrutor you can discover which are the commands that have a corresponding validator and register them automatically and BAM! You don't even need to even remember to register a new validator ever again.
      Also, if you take a look at Nick's code, you'll see that because he's working with Vertical Slices Architecture, features can group most of their functionality like command, handler and validator together in the same file, simplifying your need to locate code related to a specific request.
      Regarding to commands that don't need validation, then it's much easier as you simply make your command implement IRequest/IRequest with no validator associated and if you did your DI discovery code correctly, it should work just fine, and you wouldn't be impacting your performance with unneeded behaviors.
      A little more reading and understanding prior to criticize can do wonders.

    • @stryke0151
      @stryke0151 Рік тому +2

      @@CesarDemi81 There's nothing to implement if the idea behind why you are doing this is in my mind misguided from the start.
      There is no reason to actually move away your validation code to a seperate behaviour or pipelining it, in this way you start making sacrificies while also trying to mediate (pun intented) the downsides. By your own suggestions: moving the code closer together even in the same file. It is coupled anyway, so why not make that very obvious by just calling it from the handler.
      Resulting in readable code, no side-effects, easy debugging and when you need a slightly different way of validating or whatever you can just do that inside of that single handler.
      It seems like a good idea just like automappers but in the end its going to end in blowing up in your face later on and making it all harder to understand when you come in new to a project. Just write the damn line(s) stop trying to make these simple lines of code "clever", it does not need to be, it is JUST validation.

    • @CesarDemi81
      @CesarDemi81 Рік тому

      ​@@stryke0151 Moving it into the same file is an optional thing and more depending on each own taste. The idea of implementing FluentValidation is to make more easily understandable what fields are being validated and what are each of their rules and not a huge series of nested IFs, or calls to DB or any other dependencies cluttering my handler's logic while keeping code in different classes that can be arranged any way you want.
      Then, moving the code for calling FV validators is to reduce repetitive code: I have already done what you said, and it was a hell of a boring repetitive task when I ALWAYS needed to include the VERY SAME code at the start of each handler... And because I'm rather lazy and hate to repeat myself like a dumb, I learned to move it outside and implement it like I mentioned before. This helps me in that I just need to add the command, the handler, the validator, and then I just need to type the code I need into each one, preventing to type the very same code over and over that only clutters part of my handler because it really doesn't need to be there. This even helps me when I forget to create the validator for my command, since I make my commands inherit from a CommandBase class and my wiring includes the constraint that I need to inject a validator for these handlers, so the application will throw an error when initializing the DI container because I'm lacking dependencies and this makes it all the more robust.
      As you can see, code remains readable and also decoupled and with extremely minimum repetition of code, and my handler remains super clean with only the code required to perform its task and not a huge overhead of conditions and calls to DB/external services or to FV validator just to validate everything I need to use later.
      Automapper is a whole different story that doesn't make any sense because it hides things that can only be discovered at runtime after the app has been initialized and you need to perform the actual mapping to figure if it crashes or not because you might have forgotten something in the mapping profile, so no, it has nothing to do one thing to the other and the comparison doesn't really holds.
      Finally, I have been using this for the last 3 years and have worked in several projects with different people and everyone has been grateful to work this way and they recognize that it's much easier and cleaner to work this way rather than bunching a whole block of code in the middle of the handler like you're suggesting, so even the hands-on/empirical evidence is in favor of this.

    • @stryke0151
      @stryke0151 Рік тому

      @@CesarDemi81 Lets agree to disagree and not compare sample sizes/years/etc since thats no use anyway, you like to abstract/automate away a one liner, I do like to see that line in the "main logic" and not have dependencies on third party libraries for it.

  • @GouletGoulet
    @GouletGoulet Рік тому +13

    Great stuff Nick. I'd never seen 2 of the 3 approaches you present. It's great that you show more than one way to do things. Contrary to many of the comments I've seen so far, these approaches actually make a large code base more readable and a pleasure to work in. It doesn't "spill business logic" all over the place. The business logic hasn't moved, it's the common boiler plate in the business logic that has been extracted out, making the code easier to digest. The tradeoff is the learning curve of course but well worth it for a large code base. I think a combination of throwing the validation exception via the pre-processor and using the Result in the handler is a sweet pot where I want to be!

  • @Chris-zb5nm
    @Chris-zb5nm Рік тому +4

    I implemented this in a company. The developers are very satisfied with it.
    You can also make the middle ware a bit more general to provide more information. For example you can check if the environment to see if it's not Production and in this case, you can add even the StackTrace of exceptions to the json result, so that the devs can see the exceptions and fix them very fast.

  • @Bourn77
    @Bourn77 Рік тому +13

    Nick, please do a video on Result as return types as you used in this video, i think it can be used in C# like we have Enum type in Rust.

  • @zwickischickimicki
    @zwickischickimicki Рік тому +4

    6:17 There is no need to explicitly add validators here. I added a ValidationBehaviour class with a constructor taking an IEnumerable of all validation classes for the given command/query TRequest of the pipeline. Works really fine - you can have 0..n validators per command/query without explicitly registering each one of them.

    • @Assgier
      @Assgier Рік тому +1

      This was exactly what I was thinking as the preferred way, instead of the IValidatableRequest method as demonstrated by Nick. The latter is also pretty clever already, but it does require the query/command class to 'know' about whether or not it has validators. The method you already described solves that nicely and does indeed allow for multiple validators as well and thus smaller validation classes that each do one exact thing.

  • @ArtagonLord
    @ArtagonLord Рік тому +1

    We implemented validation in the same way on our codebase. We used preprocessors for validation and common data loading and post processors for logging and other stuff. Really powerful

  • @robertnull
    @robertnull Рік тому

    In that extension method "where TRequest : notnull" should be replaced with "where TRequest : IRequest" where IRequest is MediatR's. That adds an additional type check at call sites.

  • @pavelyeremenko4640
    @pavelyeremenko4640 Рік тому +17

    So let me reiterate,
    With this approach you have a handler and a validator. But instead of calling a validator from the handler which is obvious, you go through the whole dependency injection magic thing (I don't mind the dependency injection where it's needed, here though...) to do essentially the same thing?
    With Result, which I believe to be a superior approach to the exceptions, it gets even uglier. Now you have a handler that returns Result but it doesn't actually return this ValidationFailure. It is only there to support the dependency injection magic thing. And I think it shows pretty well where this approach goes wrong. You suddenly don't really know what your calls do and what they call.
    I hear "Cleaning" and "Separating" words thrown around, but all I see is boilerplate + magic.
    I feel like you could separate stuff by doing validation function/classes but you don't need dependency injection/mediatr/any other coordinator tool to call them cause this does break the cohesion/stack traces/debugging/readability for no real reason.
    I'm nevertheless open to the discussion. You've shown the approach, could you go over benefits which it provides that are not reachable without mediatr?

    • @nickchapsas
      @nickchapsas  Рік тому +8

      The outcome is the same but the approach is different, which is a non-argument because you can achieve the same thing with any programming language ever. "You did the same thing in a different way" is a bad argument for me. We went from having to duplicate the exact same validation code to every single validatable handler to removing that from every handle, then simply marking them as validatable through an interface and only having the validation code once. Very clear "cleaning" because you need less code, and "separating" because the validation concerns are in their own area and the business concerns are in another. ASP.NET Core is fundamentally magic. You don't see where your Controller is registered, you don't see the middleware being invoked in the pipeline and you don't see all the filters that can and will be invoked throughout the request lifecycle.

    • @pavelyeremenko4640
      @pavelyeremenko4640 Рік тому +18

      ​@@nickchapsas The argument doesn't go "You did the same thing in a different way".
      It goes "You achieved the same goal in a more magical/non-explicit way without gaining anything"
      Removing 2 explicit lines from your validation call but adding class + dependency registration, breaking compile time checking, breaking debugging(step into) and cohesion is not what I would call "less code" in a good way. Yea, it's less code in your primary handler, but is it really worth it for all that you lose?
      Validation is a part of business logic, I will fight anybody on this.

    • @z0nx
      @z0nx Рік тому +1

      @@pavelyeremenko4640 Same goes for the use of FluentValidation in itself, in my opinion. All of this looks like it is just there to avoid writing a few `if`s and the satisfaction of 'look everything samey gone'.

  • @yumyumrocks1
    @yumyumrocks1 Рік тому +28

    When we implemented this at my company and a ton of devs hated it as magic you don't easily see in the call debugging.

    • @nickchapsas
      @nickchapsas  Рік тому +27

      It's as much magic as ASP.NET Core Filters or Middleware. You don't easily see those and they are hard to debug and follow the flow too. It's what's I call "common" magic, in the sense that it's consistent with the framework you are using.

    • @dimitris470
      @dimitris470 Рік тому +13

      @@nickchapsas It not only feels like magic (like any event-dispatcher or middleware feels like), but it also spills business logic all over framework glue code. Validation should be where it belongs. Like your business code, factories or your repositories. Only validation about the request/response lifecycle should be near framework code. Like CSRF checks, since they are already tithgly dependent on the framework implementation. The same is true with configuration and how it's automated/hidden with the framework's implementation.

    • @dimitris470
      @dimitris470 Рік тому +2

      @@nickchapsas By the way, mixing business logic in the Filters or Middleware is bad for the same reason. Not only it feels like magic and is hard to follow, but again also spills business logic where it should not be. Those should be encapsulated in services and just glued together by the framework

    • @Forshen
      @Forshen Рік тому +5

      If it feels like 'magic' then you are not that far in programming or you don't understanding that part of the proces yet. I don't have the feeling of magic anymore, but I do have a lot of things I just don't understand. Which is ok.

    • @gileee
      @gileee Рік тому +6

      ​@@dimitris470 I wouldn't say the method of calling a validator is business logic. The validator itself IS business logic, and it's exactly where it should be. But how you call it is infrastructure. You could have all that in one procedure and it'd be fine I guess, maybe a few extra lines of code, but I've been using this method of handling almost everything in it's own middleware for a while now and honestly I'm not going back. Although I'm not a fan of registering everything in the Program.cs file.
      As with every framework, it's all about following the convention. If you do, everything usually works out somehow. But as always with conventions, you won't be able to do anything wherever you want and however you want.

  • @cdarrigo
    @cdarrigo Рік тому +11

    Please do a video on ConfigureAwait

  • @prom3theu581
    @prom3theu581 Рік тому +2

    I tend to use something like: public class ValidationBehavior : IPipelineBehavior where TRequest : IRequest along with
    private readonly IEnumerable _validators;
    public ValidationBehavior(IEnumerable validators) => _validators = validators;
    Then in the handle, you can just await all the validators with:
    var context = new ValidationContext(request);
    var results = await Task.WhenAll( _validators.Select(v => v.ValidateAsync(context, cancellationToken)));
    That way validators become optional for all handlers, i.e. if the service provider has none registered, you'll get an empty enumerable which won't fail resolution, and if you get any failures you can do something with the errors
    var failures = results.SelectMany(result => result.Errors).Where(f => f != null).ToList();
    return failures.Count > 0 ? throw new ValidationException(failures) : await next();
    Then we can use FluentValidation.DependencyInjectionExtensions to automatically register all validators found in a given assembly, or set of assemblies based on Markers etc

  • @dimitris470
    @dimitris470 Рік тому +13

    I do not like how implementation details are spilled all over framework glue code. It's an excellent way to make your life miserable when you have to rewrite parts or jump frameworks. Validation is part of your business logic and should be in the place where it belongs. Model validation in the business layer, factory or something. SQL injection stuff or uniqueness checks, in the repository. The only thing that makes sense to be handled near the handlers is perhaps CSRF checks and similar stuff that have to do with the request/response workflow and are tightly dependent on the framework anyway. Putting everything near framework code and hiding them behind quasi-event-dispatcher behavior simply spaghettifies code for people that will see it in a few months.

    • @user-th2qk4pt8c
      @user-th2qk4pt8c Рік тому

      hi, you mean, if we have Account entity, we will have AccountFactory to create Account and validate it right, if I understand right, please help me answer, AccountFactory belong to Domain layer right? if it is, incase I need to make sure the username in Account is unique, I have to call to AccountRepository, which is implemented in Infrastructure, is it ok for Domain to call to code from Infrastructure?

    • @dimitris470
      @dimitris470 Рік тому +2

      @@user-th2qk4pt8c Why would it not be ok? If your business layer needs to know about uniqueness, stored data is part of your business. And it needs some way to query your data layer. It's for you to decide and design the components and decide which one of them needs to know about and call other ones.

    • @CesarDemi81
      @CesarDemi81 Рік тому +1

      It's not framework code. What Nick is showing is a way to implement Vertical Slices Architecture, and the first thing you want to do is to validate the commands that are generated as a result of a new request because the idea is to fail fast instead of going all the way down into the Domain layer, where if you want to validate something against the DB you will have to find a way to do so without creating a circular reference, make your way through indirections and all the hell something like Clean Architecture forces you into. This doesn't mean that the domain entities don't need to enforce the invariants, but only at their level of responsability. And all of this is correctly applied here, so no, it's not spilled, everything is where it's supposed to be.

    • @dimitris470
      @dimitris470 Рік тому +2

      ​@@CesarDemi81 Respectfully I disagree. Staying on the same layer to do the same work does not mean you failed early. And Vertical slices do not justify moving business validations away from the business layer. If anything, Vertical slices encourages segregating your feature code. And that includes using CQRS which is a domain decision and an implementation detail that should not be entangled with framework code. Let me put it this way. Tomorrow your architecture decides that CQRS does not work nicely with your business. Or Microsoft releases a major superduper framework version and it has major architectural changes that makes all that framework functionality deprecated. How much of that code would have to be rewritten?

  • @pilotboba
    @pilotboba Рік тому +2

    Isn't it possible to register the behaviors with open generics, so you don't have to add every validation behavior to your service one at a time?

    • @craigfreeman8225
      @craigfreeman8225 Рік тому

      Thats what I do

    •  Рік тому

      Are you using a Result type then? I failed to use open generics and make it work.

  • @billy65bob
    @billy65bob Рік тому +1

    I just did a simple global filter; It checks the ModelState, and if it's invalid, it generates a validation failed response.
    I also allowed it to react if the action invalidates the model but doesn't create its own response.
    Honestly, if the payload can't even deserialise cleanly and validate per the data annotations, I genuinely don't want near a Controller's Actions.

    • @nickchapsas
      @nickchapsas  Рік тому +1

      Global filters deal with api concerns. Business logic should not go in there. Also you don’t have filters or model state on console apps, workers, mobile apps, etc

  • @KodingKuma
    @KodingKuma 4 місяці тому

    I only kept it simple, just use validation filter. And if I have to validate model else where, just call validation directly.

  • @nvmuzrowrihk
    @nvmuzrowrihk Рік тому +12

    Could you make a video on assembly trimming for both app and library projects? It's a complex topic and the MS docs don't make it easier to understand.

    • @michaelakin766
      @michaelakin766 Рік тому +1

      yes, please. Me too. I have asked for this this a few times

  • @ScottReed
    @ScottReed Рік тому +6

    Love your videos, I recently switched to Rider following your videos and know a while ago you did one but wondered if you'd consider a video on it? I'd really like to know your opinion on what settings should be changed, any tips and tricks and generally a walk through of your experience using it. Also I switched to the new beta UI which I like, what do you think on it?

    • @nickchapsas
      @nickchapsas  Рік тому +10

      My last video on this topic was quite a long time ago so I think it’s time for a follow up video on this

  • @JamesSecretofski
    @JamesSecretofski Рік тому +5

    I’m using Hellang.Middleware.ProblemDetails to register error handlers in DI

  • @tuckertcs
    @tuckertcs 4 місяці тому

    I'm confused about the preprocessor one. You mention it doesn't need to be registered, as that's done automatically, however it doesn't seem to be running for me.

  • @victorsorokovikov
    @victorsorokovikov Рік тому

    Great, I like the approach with an interface and a middleware.

  • @Reverence12389
    @Reverence12389 Рік тому

    What type of validation would you put in these validators vs what type of validation would happen in the domain class? I imagine if validation requires an external dependency then adding in a validator class would be better.
    These pipelines could probably also be used pretty well for permission checking.

  • @tanglesites
    @tanglesites Рік тому +1

    I think the larger the project gets, this kind of indirection gets confusing. After stepping through a debug session there are tabs across your monitor. I am starting to become more of the mindset, things that that go together should be together. This approach seems to be logically cohesive, and cohesion is good, but why not keep things communicationaly cohesive. If we have a chunk of code that is equivalent across mutliple namespaces, modules etc, that does not mean create another abstraction, its just a simple refactor, put it in its own method or class. Not every class needs its own file. Cohesion and Coupling is a yin and yang of writing code. This is a great video. We all do not have to think the same, but we all do have to write maintainable code, how that is done may not have to be the same either.

  • @denissorn
    @denissorn Рік тому +1

    Is this minimal or Web API? Anything wrong with using AddFluentValidationAutoValidation and implementing CommandValidator class, RuleFor().setValidator in Handlers? Less code and feels simpler, but I'm probably missing something.

  • @divyeshio
    @divyeshio Рік тому +3

    Prediction : Nick is soon going to launch an Azure course

  • @KRTone123
    @KRTone123 6 місяців тому

    I think it's a bad idea to store the command and its validation separately. What do you think about implements IValidatableObject as Command?
    IMHO it's the most cleanest way

  • @juke-duke
    @juke-duke Рік тому +4

    Website looks great, a GraphQL API tutorial would be great on it ;)

  • @patelakash50
    @patelakash50 Рік тому +1

    Can you share how you write the Result class code which accepts two return types ?

    • @loving_evil
      @loving_evil Рік тому

      ua-cam.com/video/Ve__md8LeDY/v-deo.html + ua-cam.com/video/a1ye9eGTB98/v-deo.html

  • @matthewrossee
    @matthewrossee 2 місяці тому

    But how do you return any domain-related error from the handlers? The handlers should be able to return another type of error

  • @parcanapp1193
    @parcanapp1193 Рік тому +2

    Explain the name for dometrain please. I have trouble coming up with names, so I would like to hear your thought process.

    • @samo9288
      @samo9288 Рік тому +1

      Dome means head, so dome train - head train. At least that what I think 🤣

    • @Quasindro
      @Quasindro Рік тому +2

      it trains your dome

  • @Aweklin
    @Aweklin Рік тому

    Absolutely great!!!
    Thanks Nick.

  • @ShayanFiroozi1
    @ShayanFiroozi1 Рік тому

    Hi Nick , is there any video about C# "Channels" in your youtube channel ?!
    if not please create one , what are they ? and why and how we should use them in the real world applications.
    Thank you.

  • @arunnair7584
    @arunnair7584 Рік тому

    Why not put the validation logic in the static Create factory method, or in a separate factory class. That way it will be impossible to create an object in an invalid state, and separate the creation logic of the class, from its behavior?

  • @francismarasigan108
    @francismarasigan108 Рік тому

    After you refactored your command handler to move the validation in the pipeline behavior, my concern is your method signature for Handler is still has reference to the ValidationFailed type even though its not even use anymore. Wonder if its possible to get separate signature for behavior and the command handler.

  • @MuhammadSaleem-df6ub
    @MuhammadSaleem-df6ub Рік тому

    Thanks Nick. Please keep it up.

  • @Nouriishly
    @Nouriishly Рік тому

    currently am using IpipeLineBehavior and the validationContext injecting the validators, not sure of the impact though

  • @czowiekpotencja7245
    @czowiekpotencja7245 Рік тому +1

    One of the thing im concerned about is speed ... Can you show the comparison of specific approaches? I get the code segregation and it seems nice but at the same time i always heard about speed ( for example ef and dapper which you have compared :P ) Can you show how much this abstraction cost in terms of execution??

    • @nickchapsas
      @nickchapsas  Рік тому +6

      It's very small but if you care about performance you can use Mediator which is the source generated version of MediatR which has the same exact features but compile time performance

    • @kabal911
      @kabal911 Рік тому +6

      Speed, the great “requirement myth” of general software development.
      “Oh no, this adds a couple extra microseconds to my request, it’s slow” - meanwhile the code is question is then calling the DB which is measured in milliseconds.
      Speed obviously can be an important consideration. It just isn’t for 99% of applications (on the microsecond, even millisecond level)

  • @juniorzucareli
    @juniorzucareli Рік тому

    Great video!
    Since the controller's input model is normally always the same as the "usecase", I validate my input model at the controller level through filters validating the context.modelstate.. in my case I'm not using mediatr..
    But this approach you used for those who use mediatr was really good!

  • @RoyZASTEROiD
    @RoyZASTEROiD Рік тому

    why you using validateasync place of validate? im asking as a junior, in validation async will not create any problem?

  • @Alex-fj2xu
    @Alex-fj2xu 10 місяців тому

    Isn’t it better to validate the very input of the endpoint instead of intermediary Command?

  • @francismarasigan108
    @francismarasigan108 Рік тому

    I know you have video for "Don't throw exceptions in C#. Do this instead" where you discussed the use of the `LanguageExt.Core` library that has `Result` type. This demo doesn't look it's the same `Resutl` type which that library provide. Is this something you wrote? Just watching on the video, the method return type of Result can return either A or B without design-time error. If this is another nuget library, care to share it?

  • @DF-ov1zm
    @DF-ov1zm Рік тому

    I don't get it. You had a small repository service, now it is tons of code which is basically doind exactly the same but in middleware style. What is the point? If you wanted to separate logging and validation to middleware, why not just use filters?

  • @michaelakin766
    @michaelakin766 Рік тому

    I need to do something similar, but not for MediatR, just regular services.

  • @noelfrancisco5778
    @noelfrancisco5778 Рік тому

    As always, great video. Thanks :)
    Is there a possibility to share the code you used here?

  • @ramuh9423
    @ramuh9423 Рік тому +1

    Hope nobody confuses the domain with do me train. 🤔

  • @Punisher071RUS
    @Punisher071RUS Рік тому

    Great video, thanx!
    According to the new site:
    Design ideas are good.
    You have some inconsistency in your cards: all cards have full set of rounded corners, but cards with courses are not.
    Many responsibility problems across full site.
    On tablet's and smaller sizes you have a navigation switch button. It's good, but active areas on it is very small. All active areas for buttons should be at least 40x40px.
    And also you have 7 different types of cards and problem with visual accents.
    Couple of UXUI improvements and it will be great)

  • @MsbowElite
    @MsbowElite Рік тому

    Throwing validations exceptions is not an anti-pattern? Is it compromise too much performance?

    • @nickchapsas
      @nickchapsas  Рік тому +1

      It's indeed not optimal. However, "performance" and "clean code" is contextual to each person or each team. If you're only dealing with 100 requests per second, you're not gonna have a problem at all in terms of performance.

    • @vifvrTtb0vmFtbyrM_Q
      @vifvrTtb0vmFtbyrM_Q Рік тому +1

      It seems to me that a slight performance slowdown when validation fails is not a reason for optimization.

  • @rustamhajiyev
    @rustamhajiyev Рік тому +1

    Exceptions are too expensive for validation failures. I'd go with the first approach

  • @janstv2077
    @janstv2077 Рік тому

    nice, but I think it makes the code to be now simple. a new developer that doesnt know this may waste time to understand, I dont see that is the problem with injecting IValidation interface

  • @geogeocutcut
    @geogeocutcut Рік тому

    why not use specification pattern ?

  • @hlickx4832
    @hlickx4832 Рік тому

    Hey, I am wondering, how the response will look like, if, for example, I am in register user command right now, which accepts RegisterUserRequestModel ( Username, email, password ) and I am checking, if there is already user in db with the same email and Username. How should I return this errros? Because I need to do two checks, and return all the errors. ( its just the example, approach must work in more complex scenarios. )

    • @user-th2qk4pt8c
      @user-th2qk4pt8c Рік тому

      I have a same concern, hope to hear from Nick

    • @ritchieedworthy9177
      @ritchieedworthy9177 Рік тому

      Using fluent validation you can return the specifics of the error your validator has hit. So you could have a rule for user exists and a rule for password length. Nick has a video on fluent validation from a while back.

    • @pavelyeremenko4640
      @pavelyeremenko4640 Рік тому +1

      One option would be to have a ValidationError model that has the field/message properties and then have a I[Async]Enumerable Validate method that yield returns all the errors it encounters.
      Then you effectively just call the validate method before your business logic and if it returns a non-empty collection, you return your ValidationFailure(errors) or throw a ValidationException(errors).
      It's readable, extensible, can work with mediatr but doesn't require it and it doesn't allocate additional memory before it's needed.

    • @hlickx4832
      @hlickx4832 Рік тому

      @@pavelyeremenko4640 Thank you so much. It sounds great

  • @silkfire
    @silkfire Рік тому

    Can you tell us more what's behind the name Dometrain? ^^

    • @nickchapsas
      @nickchapsas  Рік тому +2

      Make a list of 50 words that sound good, throw them in a program that makes pairs and then scroll through thousands of words until you find one that sounds cool and has an available .com domain 😂

  • @kevonhoughton1569
    @kevonhoughton1569 Рік тому

    Hey Nick, I'm a patreon subscriber, where do I find the source for this? I

  • @mhmohammadi9652
    @mhmohammadi9652 Рік тому

    awesome

  • @massaynus
    @massaynus Рік тому

    8:30 where is the extension method thats ugly
    next second, ah yes forgot i was watching nick! LOL
    Edit1
    Nick: You might have a middlewear to deal with the validation exception but im not gonna touch on that
    Also nick: proceeds to implement the middlewear

  • @adrian_franczak
    @adrian_franczak Рік тому

    minimal api filters

  • @7th_CAV_Trooper
    @7th_CAV_Trooper Рік тому

    Put your validation in your constructors and make the incorrect inexpressible. Long live DDD.

  • @doofernz
    @doofernz Рік тому

    I dont quite get the advantage of replicating the validator business logic multiple times.

    • @nickchapsas
      @nickchapsas  Рік тому

      There is no duplication. It is different validation logic per handler

    • @elpe21
      @elpe21 Рік тому

      Not sure what your level is , but create and update might have different validation rules....

  • @vifvrTtb0vmFtbyrM_Q
    @vifvrTtb0vmFtbyrM_Q Рік тому

    This is too much. An application architecture built with 90% code-separated is an anti-pattern.
    What I want to say. There are two extremes, on the one hand spaghetti code of functions is strongly related to each other. And on the other hand, decoupled code, which is so loosely coupled that it is impossible to understand it without step-by-step debugging. And debugging a simple business smeared thinly across the entire application landscape is a nightmare.

  • @TornTech1
    @TornTech1 Рік тому +1

    3rd lol

  • @justwatching6118
    @justwatching6118 Рік тому +1

    First, 17 seconds :D

  • @amirhosseinahmadi3706
    @amirhosseinahmadi3706 Рік тому +3

    No one cares about MediatR.

  • @moditrix
    @moditrix Рік тому

    Hi, I use this simple way of extension method. Works great, but I have to a contall the calling by hand, it respects attributes including custom attributes. Usage:
    request.ThrowWhenNotValid();
    It returns validated model instance to allow fluent api access.
    impl:
    public static TModel ThrowWhenNotValid(this TModel model) where TModel : class, new()
    {
    if (model == null)
    {
    throw new ArgumentNullException(nameof(model), "Model cannot be null.");
    }
    var validationContext = new ValidationContext(model);
    var validationResults = new List();
    bool isValid = Validator.TryValidateObject(model, validationContext, validationResults, true);
    if (!isValid)
    {
    var errorMessages = validationResults.Select(r => r.ErrorMessage);
    var fullErrorMessage = string.Join("; ", errorMessages);

    throw new ValidationException(fullErrorMessage);
    }
    return model;
    }

  • @TheNorthRemember
    @TheNorthRemember 7 місяців тому

    too complicated, fk medaitR