Make Your ASP.NET Core API Controllers Incredibly Simple

แชร์
ฝัง

ความคิดเห็น • 125

  • @MilanJovanovicTech
    @MilanJovanovicTech  ปีที่แล้ว +1

    Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
    Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt

    • @naldiojoaquim8920
      @naldiojoaquim8920 ปีที่แล้ว

      Why do you not create any Course about c#?

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      @@naldiojoaquim8920 Still too early to do that, in my opinion :)

  • @nayanchoudhary4353
    @nayanchoudhary4353 ปีที่แล้ว +60

    Definitely clean, but harder to understand for average developers. I would prefer somewhat balanced simplicity.

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว +8

      I'd say a quick explanation will get anyone up to speed

    • @cwevers
      @cwevers ปีที่แล้ว +4

      I agree. Also about the same amount of lines in the controller but more complex and rigid.

    • @marcinzit
      @marcinzit ปีที่แล้ว +6

      Couldn't agree more. I'd be annoying to keep explaining to new people in the project the meaning of this obfuscated code. I would pick a bit more lines of clear code over shorter, but much more complex version every time.

    • @bozin3
      @bozin3 ปีที่แล้ว +6

      The point is to understand the code without explanation. This is hard to read especially for begginers and interns even for mid developers. I still prefer the first version of the code.

    • @itzW3LF
      @itzW3LF ปีที่แล้ว +1

      That's just because Monads and FP in general are almost always ignored when learning programming. There's nothing intrinsically hard to understand about this approach (albeit monads can be tricky to grasp), you just need to get familiar with it like with everything else

  • @ewkdev
    @ewkdev ปีที่แล้ว +24

    While this is nice looking and certainly functional, i think it's not a major improvement over the controller code you showed at the start of this video. Imo, the original version does comunicate intent way better than the new version does (specifically the bind portion is something that someone looking at this code for the first time will have to investigate before they are able to understand what is actually happening). Having the match function to decide on a handler to call given a certain result type ( success vs. failure) is nice, but i would personally leave it at that and keep the rest of the code as it was.
    Anyways: Thanks for showing of the more functional approch, definitely an intersting way to do it !

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      I think if more people talked about FP it wouldn't be so confusing to people. But Bind is a straightforward concept, as is anything in FP honestly

    • @Defcon8Rolex
      @Defcon8Rolex ปีที่แล้ว +1

      How do you know that linq Where returns a filtered list? Because you're used to it. Same with bind and match

  • @GregRichardson-n6d
    @GregRichardson-n6d ปีที่แล้ว +3

    Looks nice and fancy afterwards, but by wrapping everything in static extension methods I would argue it is harder to read, debug and unit test. The original way was clean, simple, effective and easily tested.

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      Tell me you've never done functional programming before

    • @Cruize91
      @Cruize91 ปีที่แล้ว +1

      @@MilanJovanovicTech dude, I'd love to follow your content, but this response is disappointing. It's just a bit childish and unconstructive.

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      @@Cruize91 Why is it rude? The main critics of this video (and any video I create about functional programming) are people who don't do any FP. They see everything through an OOP lens, and can't admit that pure functional code cam indeed be clean, simple, effective, and easily tested.
      Oh, and don't judge a person based on one comment... 😅

    • @Cruize91
      @Cruize91 ปีที่แล้ว +2

      ​@@MilanJovanovicTech I didn't judge your person at all. I criticized the response.
      Secondly, you're putting words in my mouth. I didn't say 'rude'.
      You have two commenters here who are genuinely trying to interact with you and your content.
      The first comment was simply a voice of not understanding. You could've handled that so much better by replying with a friendly stock answer, if this is something that occurs so often.
      Secondly, I'm simply stating that I disagree with this kind of response, because aren't we here to learn? A guy comments with some genuine concerns, so it's a chance to educate nicely.
      I'm not saying this to scold you, I'm just saying that I like your content, and would like to keep following it, but this kind of behavior is gonna turn me away.

  • @morganskinner3863
    @morganskinner3863 ปีที่แล้ว +2

    We have been discussing this very thing at work and I really like your solution here. I’ve a feeling we will be using exactly this in our controllers from now on. Thanks for the video, it’s excellent!

  • @VladyslavHorbachov
    @VladyslavHorbachov ปีที่แล้ว +7

    I would prefer to have the old version for 3 reasons: easy to read, easy to debug, looks native.

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว +2

      Only because most people are not used to FP style code. Otherwise, this is also easy to read, and if anything it's even easier to read, since it follows a very natural flow from step to the other.

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      @@michbushi Try a little rxjs or Reactive Extensions for .NET then come back to this. It's a mindset shift.

  • @itzW3LF
    @itzW3LF ปีที่แล้ว +1

    Man I'm so glad I took a functional programming course last semester at my Uni, monads are so awesome!

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว +2

      Man, I wish they taught FP in my uni when I studied 😂

  • @mohsinazamafridi8566
    @mohsinazamafridi8566 ปีที่แล้ว +4

    Milan Nice Explanation.
    One Suggestion , like you're using already created project for Video.
    I think it's hard for viewers to understand when you start coding in already created classes etc.
    I think it will be good if you demo it in sample small project.
    it will be easy to understand. :)

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว +2

      I don't really have the luxury of going over a project from scratch in every video, since they would be too long and people would lose interest. :/

  • @javidibra6786
    @javidibra6786 6 หลายเดือนก่อน

    Man your contents are just amazing.keep it up. good luck!

  • @topx777
    @topx777 ปีที่แล้ว +1

    Amazing content! You’re always surprise me with very useful content, thanks!

  • @shadowsir
    @shadowsir ปีที่แล้ว +4

    You've created a Result monad. This comes out of the box in most functional languages. It's such a round-about way of doing it in C# that I usually just don't bother writing all of the "extra code to make it more F#'y".
    The Result class makes it possible to make a distinction between an expected (validation / domain) error and an actual unexpected exception (e.g. the database is down or we accidently introduced a bug).

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      I find it worthwhile going through the trouble, since I'm a fan of FP in C#

    • @shadowsir
      @shadowsir ปีที่แล้ว

      @@MilanJovanovicTech fair enough.

  • @kodindoyannick5328
    @kodindoyannick5328 7 หลายเดือนก่อน +1

    Super content. Thank you!, Milan

  • @ramytawfik9168
    @ramytawfik9168 ปีที่แล้ว +1

    Can you make a series on functional programming important concepts Milan ?

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      I just recorded one more about ROP, releasing in a few weeks

    • @ramytawfik9168
      @ramytawfik9168 ปีที่แล้ว

      @@MilanJovanovicTech Thanks very much for all your effort

  • @cyrilw1
    @cyrilw1 ปีที่แล้ว +1

    Great job Milan. Would be great to see a GraphQL video soon

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      That's on my learning list, since I didn't work with GraphQL before

  • @arthurfedotiew3609
    @arthurfedotiew3609 ปีที่แล้ว +2

    @MilanJovanovicTech, that is a super clean and easy to read design, thanks for your great ideas and inspirations. Don't pay to much attention to ones who say it's complex and unreadable. Even for average mind as mine it is quite straightforward (even given I have started to learn c# dotnet a few month ago).
    I could only think of better name for Bind, like Execute, but probably you have some convention as I see you always do in dotnet)

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      I have a few more videos on ROP, so if you're up for it check them out:
      - th-cam.com/video/dDasAmowFts/w-d-xo.html
      - th-cam.com/video/zuy2j8vxgYc/w-d-xo.html
      - th-cam.com/video/vGkgsduwnc4/w-d-xo.html

  • @faximori
    @faximori ปีที่แล้ว +1

    We receive REST payload object to create another request inside controller and process it somewhere else? Well... It's far better to encapsulate logic in minimal API or FastEndpoints than using another layer.

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      One is external (public) to the API, the other is internal to your application

  • @vitek0585
    @vitek0585 ปีที่แล้ว +2

    I prefer fluent way as well, but performance has to be taken into consideration if it’s a priority 🚀

  • @branislavpetrovic7486
    @branislavpetrovic7486 ปีที่แล้ว +2

    Great idea for refactoring! Could you make a introduction video on monads and discriminated unions in C#?

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว +1

      I think Zoran Horvat is much more adept to talk about those subjects, but I'll give it a try why not 😁

  • @user-rp9iis1en6h
    @user-rp9iis1en6h ปีที่แล้ว +1

    Please make a video on how to implement identity server with role based auth + how to check the role conditionally in a common/shared method

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      I was thinking of covering some other IDP actually

  • @jbb4play
    @jbb4play ปีที่แล้ว +1

    On a side note, what is the benefit of using that pattern, is it simply to adhere to the "Clean architecture setup"?
    Performance wise, how is this better/worse than simply having some interface IService with method DoSomething(), and then injecting that service into the application?
    Of course I think the way you do it in this video is nice, but it also requires a little more boilerplate to get running.
    And lastly, thanks for the videos, I love them :)

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      Performance wise it's slightly worse, because of more allocations and method calls.
      But FP is very nice to work with, although it takes some time getting used to.
      The end result is the same. I'm just trying to raise awareness about FP.

  • @delegatethings
    @delegatethings ปีที่แล้ว +1

    Thanks for this content. Any suggestions on how to learn FP please tell us.

  • @S3Kglitches
    @S3Kglitches ปีที่แล้ว +1

    How do you not have to write authentication scheme on the controller function? Which one is picked as default? If you only have one active, will it be picked as default?

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว +1

      You can place it on controller level

    • @S3Kglitches
      @S3Kglitches ปีที่แล้ว

      @@MilanJovanovicTech ah, I missed that!

  • @hysapod
    @hysapod 8 หลายเดือนก่อน

    Hvala puno na lekciji! Chao iz Rusije.

  • @kebbbek
    @kebbbek ปีที่แล้ว +4

    I think that instead of creating additional abstraction with those Bind and Match methods it could be simplified just by not going back to the controller with IsFailure, Value, Errors properties, instead returning the actual result (value) from the query and just a Task from command, and if there is a validation/business logic error - just thrown an exception with proper context and handle it to returned desired code & message
    in this way in the controller it would be just a 2 liner:

    public async Task UpdateMember(Guid id, [FromBody] UpdateMemberRequest request, CancellationToken cancellationToken)
    {
    await Sender.Send(request);
    return NoContent();
    }

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      Why would I have a Result object then - which is expressive - and obscure it with throwing an exception somewhere in the code?

    • @kebbbek
      @kebbbek ปีที่แล้ว

      @@MilanJovanovicTech let's assume that you send a command that violates some business rules that are checked in the domain layer, in this approach instead of throwing an exception, you have to pass information up from the domain layer about whether it failed or not, thus coupling domain, application and presentation layers by branching the 'IsFailure' property

  • @fieryscorpion
    @fieryscorpion ปีที่แล้ว +6

    This is just way too complicated, my goodness.

  • @hamitkarahan2973
    @hamitkarahan2973 ปีที่แล้ว +1

    Hi Milan, nice and efficient work, thanks for sharing it! I see you are using CancellationToken parameter in your Post Methods. I heard that we should not be using CancellationToken in our Post Methods because of in case of cancel there may be an inconsistency in the data as a result of the process being interrupted. What do you think about this?

  • @unskeptable
    @unskeptable ปีที่แล้ว +1

    I would prefer the first approach as well . Just keep it simple.

  • @krccmsitp2884
    @krccmsitp2884 ปีที่แล้ว +1

    I like it. 🙂

  • @MB-Kajtech
    @MB-Kajtech ปีที่แล้ว +3

    Love this with the ErrorOr library, have something very similar in place currently. In my opinion throwing Exceptions for errors which are expected (we know about) is logically incoherent since they are not exceptional in nature. What's your take on Errors vs Exceptions?

  • @Scifer
    @Scifer ปีที่แล้ว +1

    Nice video! Btw, what's the name of you VS theme?

  • @rohit704
    @rohit704 ปีที่แล้ว +1

    Can you please make some videos on aws cloud formation + azure pipeline using .Net core , Wanted detail video how API triggers lambda through cloud formation.

  • @nove1398
    @nove1398 ปีที่แล้ว +4

    Nice thumbnail haha

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว +1

      Glad I'm finally getting better at making them 😁

  • @jsnatureclicks3185
    @jsnatureclicks3185 ปีที่แล้ว +1

    Is await must for async functions?

  • @vivekkaushik9508
    @vivekkaushik9508 ปีที่แล้ว +1

    Hi Milan. As much as I love the extension methods and the flexibility and clean code practices they bring to the codebase I'm skeptical of their impact on performance/memory. Static classes gets instantiated as soon as the application starts and they live in heap memory throughout application's lifetime. I'm not sure if using too many static classes/methods is going to have a significant impact on application's performance as it will cause frequent GC triggers? Correct me if I'm wrong please. Thankyou.

    • @krccmsitp2884
      @krccmsitp2884 ปีที่แล้ว

      Static classes get never instantiated, since no objects are created thereby.

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว +1

      We have bigger problems to solve than a few extra allocations/method calls

    • @vivekkaushik9508
      @vivekkaushik9508 ปีที่แล้ว

      @@krccmsitp2884 But they live in heap memory forever. Sorry used the incorrect term 'instantiation'. One can say intilization I guess?

    • @vivekkaushik9508
      @vivekkaushik9508 ปีที่แล้ว

      @@MilanJovanovicTech That's where Nick and you might differ I guess. But I agree most clients are either unaware of or simply don't care about memory efficiency and performance. They just want working solution with minimal overhead.

    • @krccmsitp2884
      @krccmsitp2884 ปีที่แล้ว

      @@vivekkaushik9508 there's no heap allocation involved with static classes since there's no memory consumption necessary.

  • @zameer.vighio
    @zameer.vighio ปีที่แล้ว +2

    Good work, every video we enjoy and learn something new & interesting,
    but what if think about time complexity, we usually try to make our codes more simple making reops or like this stuff,
    but is it suitable way keeping DATA-STRUCTURE/ALGORITHMS/TIME-COMPLEXITY/ in mind....
    please guide.
    Thanks.

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      You'll find that such optimizations are negligible for most applications

    • @zameer.vighio
      @zameer.vighio ปีที่แล้ว +1

      @@MilanJovanovicTech yup That's also point... Well thanks buddy

  • @gardnerjens
    @gardnerjens ปีที่แล้ว +1

    that is selectmany right?

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      What is?

    • @gardnerjens
      @gardnerjens ปีที่แล้ว

      @@MilanJovanovicTech bind i think is the same as .SelectMany, also i think if you name it that insted of bind you can use the "from" "in" keywords

  • @YuriWithowsky
    @YuriWithowsky ปีที่แล้ว +1

    Hello Millan! Thanks for the great new video! I always share your videos with my friends in Brazil :)
    So I have a question, what do you think about adding a mapper from your DTO to Commands/Queries? like AutoMapper.
    I think your controller will have less lines of code, is that a good idea?

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      I prefer keeping it light on the mappers, and just call constructors directly. And if I do use mapper, I use a dynamic one like Maspter

    • @pilotboba
      @pilotboba ปีที่แล้ว

      Prefer/try explicit (or implicit) operators to your DTOs to do the mapping. Yes, you have to write the mapping code yourself, but that's a good thing, especially when it comes to static analysis and debugging.

    •  ปีที่แล้ว +1

      You can try mapperly, it uses source generators to create static mapping. So at any point you can remove it, and keep the code. It also does not hide references behind reflection. Drawback is that it does not support everything that Mapster does, ex. projections.

  • @Defcon8Rolex
    @Defcon8Rolex ปีที่แล้ว +1

    Hello Milan,
    Love the content.
    What do you think about LanguageExt library? Have you thought about doing a video on that?

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      I think it's great, although I didn't use it before

  • @marklnz
    @marklnz ปีที่แล้ว +2

    Interesting approach, but I wonder why go to all this trouble when you'd be able to achieve arguably a similar result using Minimal APIs. Also you really should have validation in there somewhere...

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว +1

      Spreading awareness about FP :)

    • @marklnz
      @marklnz ปีที่แล้ว

      @@MilanJovanovicTech fair enough. Could do the same with minimal as well tho 😉

    • @kabal911
      @kabal911 ปีที่แล้ว

      I don’t see how any of the code in a minimal api would be different/simpler at all. You would just be using Results.* instead of ActionResult.
      The body of a minimal API and a controller action are identical, they are functions

  • @charles_kuperus
    @charles_kuperus ปีที่แล้ว +1

    Wow nice method. I would love to see this on minimal API's of dotnet

  • @RonyCuzco
    @RonyCuzco ปีที่แล้ว +1

    Why use fp over oop?

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว +1

      Because FP is simply awesome

    • @S3Kglitches
      @S3Kglitches ปีที่แล้ว +1

      @@MilanJovanovicTech That's not a good reason.

  • @ucretsiztakipci6612
    @ucretsiztakipci6612 ปีที่แล้ว +1

    Does not extendable for other requirements.

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      FP is much MORE extendable than OOP - just add another function :)

    • @ucretsiztakipci6612
      @ucretsiztakipci6612 ปีที่แล้ว

      @@MilanJovanovicTech No it is not. Sctricly Typed languages are horrible for the FP!

  • @weifengmao
    @weifengmao ปีที่แล้ว +1

    That looks similar to the oneof lib

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      It's called a Monad, and it's a concept from FP. That's why it looks similar

  • @alukardishe
    @alukardishe ปีที่แล้ว +2

    Readable and understanding vs thin controller. And you failed I think)
    But you show me interesting solution

  • @MortvmMM
    @MortvmMM ปีที่แล้ว +1

    I wished before the video that its not MediatR. Not that I don't like it, just hoped for something new

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว +1

      Haha, sorry to disappoint! 🤣

    • @MortvmMM
      @MortvmMM ปีที่แล้ว

      @@MilanJovanovicTech don't worry 😂 it's not your fault they didn't come up with something better yet