Write cleaner APIs in .NET 7 with MediatR

Sdílet
Vložit
  • čas přidán 3. 08. 2022
  • Get started with Octopus Deploy: oc.to/nickchapsas
    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 very easily integrate .NET's Minimal APIs with MediatR using the brand new .NET 7 AsParameters attribute in a very elegant and testable way.
    This video is sponsored by Octopus Deploy
    Don't forget to comment, like and subscribe :)
    Social Media:
    Follow me on GitHub: bit.ly/ChapsasGitHub
    Follow me on Twitter: bit.ly/ChapsasTwitter
    Connect on LinkedIn: bit.ly/ChapsasLinkedIn
    Keep coding merch: keepcoding.shop
    #csharp #dotnet #dotnet7

Komentáře • 243

  • @nickchapsas
    @nickchapsas  Před rokem +303

    I want to formally apologise to everyone for using age=60 in the video. 0 and 9 and next to each other and I missclicked the button and only noticed during editing. I can do better.

    • @weluvmusicz
      @weluvmusicz Před rokem +1

      wait what? :D

    • @barloc2
      @barloc2 Před rokem +14

      Apologies accepted. We are all human beings, mistakes can happen.

    • @pdevito
      @pdevito Před rokem +4

      Ruined

    • @redouane5626
      @redouane5626 Před rokem +14

      you should apalogize for naming it MinimalatR 😑

    • @dungimon1912
      @dungimon1912 Před rokem +1

      huh?

  • @buriedstpatrick2294
    @buriedstpatrick2294 Před rokem +23

    To make your code even neater, remember you can use records instead of classes for your MediatR requests.

    • @Suriprofz
      @Suriprofz Před rokem +3

      And make them immutable.

    • @aj.arunkumar
      @aj.arunkumar Před 2 měsíci

      i have a question regarding records.. are domain entities supposed to be defined using records ? if so, we cant use EF with records, so what are we supposed to do..? create separate classes for EF and do mapping ?

  • @qwer1234cvb
    @qwer1234cvb Před rokem +8

    Instead of separating requests and handlers in different folders (or even different files), I find it way more convenient to put both query and handler into the same static class. E.g.
    ```
    public static class GetUsers
    {
    public record Query(int Age) : IRequest;
    public class Handler : IRequestHandler { ... }
    }
    ```
    It becomes very handy when you need to go to definition by F12, or when writing tests and can add the static to usings and then operate with just Query and Handler, without those long names.

  • @barloc2
    @barloc2 Před rokem +47

    The first example for the age mapping was 60 instead of 69.
    I hope everything is OK with you Nick, you don't seem to be yourself nowadays.

    • @nickchapsas
      @nickchapsas  Před rokem +22

      I MISS CLICKED THE BUTTON DON'T JUDGE ME

  • @benjamincharlton3774
    @benjamincharlton3774 Před rokem +6

    Brilliant, interesting, engaging as always. Thank you, Nick! If you'll accept some respectful, constructive criticism, it is that your latest videos are presented too quickly. Anybody genuinely interested in what you're doing has to pause and rewind and pause again multiple times. You're clicking and typing at the same speed as you would be if you were working, not teaching. I hope the feedback is helpful.

    • @pilotboba
      @pilotboba Před rokem

      Or use the speed controls on the viewer. I watch 99% of my content at either 1.5x or 1.75x depending on the presenter. But there are options to slow the vid too.

  • @CarmenSantiNova
    @CarmenSantiNova Před rokem +2

    Great video as always!
    We have been using this exact scheme for a while now (1-1.5 years) in production and it works as a charm.
    We only have one webapi endpoint in our system that handles all requests (not entirely true but ask if you want to know more about it). Everything is POST:ed to the server, so we do not use the verbs.
    And the posted object from the client is normalized as such (serialized via JSON) and defined in TypeScript:
    class Message {
    string Type;
    object Data; // JSON Serialized data
    }
    This means that we do not have to map endpoints on the backend. We only register handlers to the mediator, i.e. MediatR (which we've replaced with MassTransit).
    On the client side all the types supported are mapped just like you would map endpoints on the backend.
    The reason is that different types might be handled by different endpoints (domains basically).
    I would argue that protocol specifics (such as web urls and parameter formats) are not a concern that the user of the request client should handle.
    // Usage on the client side.
    _ourRequestClient.Send(new CreateUserRequest() { Name = "A", Age = 10 });
    What you have reached in your code is a protocol agnostic solution where the handlers doesn't know anything about i.e. webapi. By doing so, you can now easily replace the webapi with i.e. gRPC or even an eventbus solution.
    So be very careful not to introduce webapi (or any protocol specific stuff) in your handler. So the IResult should definitely be replaced with an abstraction that can be mapped into IResult since that is WebApi specific.

  • @SamueleFurnari
    @SamueleFurnari Před rokem +2

    I love, suggest and use this approach in all my projects, exept the demo projects. i call this a little design overhead that gift us the testability, SOLID patterns application and so better code. great video Nick! 💪

  • @StigBrembo
    @StigBrembo Před rokem

    Love this! I changed your extension method a bit, so I could make use of the OutputCache in .Net7 too.

  • @andrewalexopoulos921
    @andrewalexopoulos921 Před rokem

    Great video as always! Nice usage of mediatr lib as well :)

  • @bernardo44250
    @bernardo44250 Před rokem

    I didn't know this video existed! Thanks bro! Really grateful.

  • @Velociapcior
    @Velociapcior Před rokem

    This is in my opinion single handedely the best way to create Minimal Api, can't wait to show this to my colleauges. You are MVP Nick. Microsoft MVP

    • @DrCox-xx8tu
      @DrCox-xx8tu Před rokem

      I prefer FastEndpoints to build APIs. You might want to give it a look as well.

  • @pablocom
    @pablocom Před rokem

    Loving this new .NET 7 feature

  • @antonmartyniuk
    @antonmartyniuk Před rokem

    It looks nice, a Mediator way to structure the minimal APIs. Minimal APIs + MediatR = ❤️

  • @FraserMcLean81
    @FraserMcLean81 Před rokem +1

    Awesome feature and video, thanks Nick! I am interested to know more about how you would automatically register endpoints using the HttpGet and other attributes.

  • @framidox3757
    @framidox3757 Před rokem

    You are a life saver! Kudos to you! You rock!!

  • @wojciechwilimowski985

    You made the middle ground between classic and minimal APIs - minimal controllers!

  • @taufikdev88
    @taufikdev88 Před 9 měsíci

    love the way you create an extensions class for registering everything

  • @nocgod
    @nocgod Před rokem +3

    Very interesting, looks like without controllers we are seeking the same structure.
    Would be interesting to investigate the performance diff (mem, CPU, through put) between minimalApi, minimatorApi, webApi (controllers)

  • @karthiksrivatsa8243
    @karthiksrivatsa8243 Před rokem +1

    We can generate swagger documentation as well and also use fluent validation. Combining all these will definitely make cleaner API.

  • @digitalhome6575
    @digitalhome6575 Před rokem +3

    Love it, learned it, living it, however.. you need a follow-up video on how/where to add swagger documentation attributes on this. I'm currently extending on your example to add some fluentvalidation to this, and once I figure out the swagger docs thing, microservices will by flying left & right :)

  • @scottatkinson7083
    @scottatkinson7083 Před rokem

    Hey Nick, really enjoying the content so far. Just wondered what courses you're planning on bringing out soon?

  • @Mikebutawski
    @Mikebutawski Před rokem

    This was just awesome! Thanks a lot!

  • @amantinband
    @amantinband Před rokem +2

    That's very clever, actually. One of the reasons I split Contracts from MediatR requests is that the request can't always capture all the data sent from the client. This concept, with some tweaking, has the potential to be a fun library 🤙🏼

    • @nickchapsas
      @nickchapsas  Před rokem +2

      With this approach you can capture everything. Query string with [FromQuery], body with [FromBody], form with [FromForm], headers with [FromHeader] and route with [FromRoute] so there is nothing you'll be missing here.

    • @drewkillion2812
      @drewkillion2812 Před rokem +1

      @@nickchapsas there is also the HttpContextAccessor as well

  • @victor_pogor
    @victor_pogor Před rokem +5

    Amazing video. I remember in one live session when you discussed the minimal APIs, I mentioned that this could be used with MediatR (to keep the endpoints clean and to move the handlers for example in core/application layer), and you said something like "why would you use another handler if you have the minimal API handler (delegate)" ))

    • @nickchapsas
      @nickchapsas  Před rokem +2

      Don't think of this as an application layer. This is still the UI/API layer. It is just more testable and strucuted

    • @victor_pogor
      @victor_pogor Před rokem

      This is a presentation layer, I meant to move the handlers in an aplication layer (in context of clean architecture) and keep the presentation layer as simple as possible.

    • @nickchapsas
      @nickchapsas  Před rokem +2

      @@victor_pogor You can structure your project however you want. In the concext of the video mediatr is used on the presentation layer. If you wanna split that then go for it.

  • @TimurMANDALI
    @TimurMANDALI Před rokem +3

    Awesome video, thanks Nick! , for .NET6 users :
    public record ExampleRequest(int? Age, string? Name) : IHttpRequest
    {
    public static ValueTask BindAsync(HttpContext context)
    => ValueTask.FromResult(new (
    Age: int.TryParse(context.Request.Query["age"], out var age) ? age : null,
    Name: context.Request.RouteValues.TryGetValue("name", out var name) ? (string?) name : null
    ));
    }

  • @tonongah102
    @tonongah102 Před rokem

    Thanks bro that was really helpful

  • @xian9029
    @xian9029 Před rokem

    Very helpful..thanks a lot.

  • @paulward8087
    @paulward8087 Před rokem

    Reminds me of a CQRS approach I toyed with some time ago.

  • @jonholt8429
    @jonholt8429 Před rokem +1

    This is appealing, and gets me one step closer to ditching the controller for a minimal api. The other barriers to me are Swagger support (can this be easily added for minimal API?) and company policy on non-LTS versions (saw your video on that and agree, but wheels of change can turn slowly)

    • @akzual50
      @akzual50 Před rokem

      You should be able to facilitate that based on the swagger ext method which does it for controllers

  • @AyahuascaCeremony
    @AyahuascaCeremony Před rokem

    Another great video. Towards the end you mentioned the idea of not depending on IResult in your Handlers but using a mapper instead. Could you do a short video to explain that and how to implement it? TIA

    • @nickchapsas
      @nickchapsas  Před rokem +4

      I will be making a video on that topic indeed

  •  Před rokem

    Nice video. I was just looking at FastEndpoints and they seem to provide very similar functionality but they are available on version .NET Core 6 which is pretty cool.

    • @nickchapsas
      @nickchapsas  Před rokem +2

      FE is my personal prefered and recommended way to build apis in .NET.

  • @obiwanjacobi
    @obiwanjacobi Před rokem

    Nice one!

  • @diligencehumility6971

    Great video and great usage of MediatR. But you do end up with all your application logic living inside the API project. And then we are back to clean architecture

  • @bryanlewis3643
    @bryanlewis3643 Před rokem +1

    Nick, how would you compare this to FastEndpoints? We have used Mediatr in the past with a traditional Controller full of mediatr calls for each endpoint, and I recently created a proof of concept using FastEndpoints. This seems to be a bit of the merging of the two. What advantages/disadvantages do you see with this new idea over FE?

    • @nickchapsas
      @nickchapsas  Před rokem +4

      I prefer FastEndpoints. It is faster, has full support for all the things you will ever need and it gives a better overall experience. This is just if you wanna build something simple with a little bit of strucute. FE is still my favourite and recommended way of building APIs in .NET

  • @jamesmussett
    @jamesmussett Před rokem +12

    I recommend forwarding the CancellationToken to mediator from the delegate, otherwise it will just use the default CancelationToken in the handler.

    • @nickchapsas
      @nickchapsas  Před rokem +5

      Yeah without passing the CT from the handler's patameter's to the Send call, the cancellation won't be triggered

    • @sergiik2168
      @sergiik2168 Před rokem +1

      You may inject some own CancellationTokenProvider service, which would get CancellationToken from HttpRequest.RequestAborted, directly to infrastructure layer (like repositories or custom clients to 3rd party services). In that way you don't need to pass CancellationToken from controllers to (i.e.) repositories through business layer at all.

    • @PanzerFaustFurious
      @PanzerFaustFurious Před rokem +1

      That's why I recommend to set "CA2016: Forward the CancellationToken parameter to methods that take one" to "warning" severity.

    • @Gobba61
      @Gobba61 Před rokem

      Could you elaborate on how you do this if you dont mind?

  • @ADSNGreenLife
    @ADSNGreenLife Před rokem

    Nick you are dam good man!! bravo

  • @cmartinez4727
    @cmartinez4727 Před rokem

    Is mapget() better than doing it old school via apicontroller? Or is mapget more for small project while apicontroller classes is better for big projects?

  • @kippie86
    @kippie86 Před rokem +1

    I can't really find much documentation about the AsParametersAttribute. From which sources does it map values? Is it possible to pass in values from a custom ValueProvider? In my case many controllers have a [FromClaims] attribute on one or more parameters, and it would be great if those could just automatically be mapped into my IRequests

    • @nickchapsas
      @nickchapsas  Před rokem +3

      All [FromXXX] attributes work inside the request

  • @kasperkadzielawa8658
    @kasperkadzielawa8658 Před rokem

    Just a few more steps and you reinvent the classic controller class approach xP

  • @krccmsitp2884
    @krccmsitp2884 Před rokem

    Veeery nice! 👍

  • @DevonLehmanJ
    @DevonLehmanJ Před rokem +1

    I don't generally like using either minimal apis nor mediatr, but this combo makes it much more appealing

    • @EternalVids
      @EternalVids Před rokem

      Out of curiosity, what are your reasons for disliking MediatR?

    • @DevonLehmanJ
      @DevonLehmanJ Před rokem

      @@EternalVids I haven't used it much, but from my understanding: if i had a service method e.g. "AddObject", and I wanted to call that from a controller, that's all great. The handler will update the database and do everything it needs to do.
      But now suppose that I have some other endpoint where i need to add both AddObject and AddChildObject. Now I either: need a new handler to do both, or i need to embed one handler inside another, or I need to create two separate requests to save each object. This would result in two separate database saves, and all the other one-time cruft.
      In addition, i would find it annoying to have to say "new Request().Handle()" (or however you trigger mediator), rather than just calling _myInjectedService.Method().
      This gives me a lot more flexibility to re-use code within your injected services, and also makes the code much more navigable as i can do Go To Implementation on a method, but not on a call to mediatr.

    • @EternalVids
      @EternalVids Před rokem

      @@DevonLehmanJ I guess it's a tradeoff. Using MediatR saves you from having to inject those individual services into your WebApi controller classes. MetiatR takes care of the injection for you, so all you need to do is just call the _mediator.Send(request), without worrying who (or multiple whos) handles the details. Also typically you don't need to create a Request object yourself, depending on how your queries are structured. I personally just use Endpoint([FromQuery] request), and pass the resulting object directly to MediatR. You end up almost no code in your controller classes this way, it all fits into single line expression body statements for each.
      public Task Get([FromQuery] Request request) => _mediator.Send(request);
      Personally my only pain-point is the fact that it's not easy to navigate from the WebApi mediatr invocation to the actual handler. I've seen people placing Handlers in the same files as Request definitions as a workaround, but I am not convinced that's the best way.

    • @kabal911
      @kabal911 Před rokem +2

      @@EternalVids I think it definitely is the best way, combining them.
      The same as in a traditional controller. The “HttpGet” attribute and the controller method signature is kind of the request, while the method/body is the handler.
      We even store our FluentValidation implementations for our requests with the request and the handler. They are all connected.
      As a trade off, you could store them in different files in the same folder, aka structure by feature. Structure by type for me is just not a good architecture, when it comes to application business logic. I still do however keep the controllers in a controller folder, mostly because I haven’t thought too much about that side.
      But it doesn’t really matter, just what you and your team is comfortable with and is most productive with.

  • @rade6063
    @rade6063 Před rokem

    Now that you can use mediator, fast endpoints, and others like you showed here and on course which will you use as your go to solution/template?

    • @nickchapsas
      @nickchapsas  Před rokem +1

      Fast endpoints is still my go to. It is faster and has way more functionality and better structure. This is more of just a simple alternative if you wanna hack something together and still have some structure

  • @VinayKumar-ki5fd
    @VinayKumar-ki5fd Před rokem

    Very gooood :)

  • @isnakolah
    @isnakolah Před rokem

    Hey Nick, great video. How though do you get your rider working with .NET 7?

    • @nickchapsas
      @nickchapsas  Před rokem

      Never had a problem wth it not running. I'm not even on the EAP

    • @isnakolah
      @isnakolah Před rokem

      @@nickchapsas I found my issue, I kept on installing the x86 version instead of x64. I now know better

  • @idzyubin720
    @idzyubin720 Před rokem +1

    Great job!
    So, maybe let’s consider pros & cons of mediatR? As I know, it has some problems with performance and memory
    Maybe, is there alternative tool?

    • @kippie86
      @kippie86 Před rokem +1

      Nick already talked about the performance of MediatR in this video: czcams.com/video/baiH3f_TFfY/video.html

    • @idzyubin720
      @idzyubin720 Před rokem

      @@kippie86 thanks, I’ve seen this video yet

  • @maacpiash
    @maacpiash Před rokem

    I have been keeping the handler methods of my minimal APIs inside static classes as static methods, as described in 2:00. Is there going to be a problem in terms of scopes?

    • @nickchapsas
      @nickchapsas  Před rokem

      No there isn't, as long as you injecting everything through the handler's parameters

  • @marcomannarino7930
    @marcomannarino7930 Před rokem

    Nice:)

  • @jonathanperis3600
    @jonathanperis3600 Před rokem

    Can we have IResult out of AspNetCore project to build this inside a shared library?

  • @thespicycoder5583
    @thespicycoder5583 Před rokem

    Nick, can you please do a mini series on Dapr

  • @RuslanSafroniuk
    @RuslanSafroniuk Před rokem

    Hello! How about put request with first parameter from route and second parameter from body?

  • @daxyhrgaming5292
    @daxyhrgaming5292 Před rokem

    I really liked this approach, but when fiddling around with this, I seem to run into issues when I combine this with the ValueOf package that you demonstrated a while ago. I already added the TryParse function to my objects, but I’m still getting weird behavior (like objects are being expected instead of strings).

    • @nickchapsas
      @nickchapsas  Před rokem

      You wouldn’t combine this with ValueOf

  • @endmrx
    @endmrx Před rokem

    Thanks for the news!
    Minor: await Task.Delay(...); → await Task.CompletedTask; ?

  • @volodymyrliashenko1024

    Hello Nick, do you know any big open source project where MediatR is used?
    I would like to see how it looks.
    Thanks!

    • @Lammot
      @Lammot Před rokem

      There's always eShopOnContainers.

    • @suleymanov1990
      @suleymanov1990 Před rokem

      Also CleanArchitecture template and NorthwindWindTraders from Jason Tyler.

  • @JonathanPeel
    @JonathanPeel Před rokem

    Is there a way to program minimal API on an interface, and then easily create a client, based on the interface?

  • @GleichCraft
    @GleichCraft Před rokem +6

    Cool Stuff! Thanks your for your great content. I think this is a great approach, but I do not agree with putting the IResult in the handler. By returning IResult in the handler, you force the consumer of the IRequest (mediator) to use HTTP. If you later on decide to build a CLI out of your api, use SignalR instead of http or something else you cannot without dealing with an HTTP Object (IResult). So I perfer either returning the mapped DTO (Response) or returning the domain object which then needs to be mapped by the API controller/ minimal api lamda (what ever you want to call that :D), but this depends on wether you need this extra mapping layer in your application (most dont, so we should be practical). I think the benefit of returning IResult is so small compared to the crazy http contract you are forcing. What do you think?

    • @nickchapsas
      @nickchapsas  Před rokem +9

      There is no application later in this example so where the IResult lives doesn’t matter. Stop thinking like clean architecture is the only way to build software. It’s not

  • @michaelfernandes6893
    @michaelfernandes6893 Před rokem

    Is this not an example to couple youre frontend end to youre backend as a bad practice?

  • @miindgame
    @miindgame Před rokem

    Let's say I have a Clean Architecture type project, but would like the minimal API approach instead of all the separate Controller.cs files.
    And let's say, my old controllers handle a result monad to give the appropriate responses (200,404,500, whatever). Would it even be possible to then use only one mediatR handler on the presentation layer?

    • @nickchapsas
      @nickchapsas  Před rokem

      One handelr per request not one handler for all requests

    • @miindgame
      @miindgame Před rokem

      @@nickchapsas Ah of course, MediatR in the presentation layer should then just mediate the separate files I used to have. And those will still follow the rules they used to do when they were in separate files. Thank you! :)

  • @joephillips6634
    @joephillips6634 Před rokem

    thanks dad

  • @bjarkeistruppedersen8213

    Does this work with the new MapGroup they added to v7?

    • @nickchapsas
      @nickchapsas  Před rokem +1

      Yeah can't see why that might be a problem

  • @VijayKumar-wy9ku
    @VijayKumar-wy9ku Před 6 měsíci

    Isn't it increasing the boiler plate? You are gonna have n handlers(classses) for n endpoints.

  • @samsonquaye9913
    @samsonquaye9913 Před rokem

    How do we handle post?

  • @Arkensor
    @Arkensor Před rokem

    What is your opinion on this kind of "seperation of configuration" with that you often need to put something explictly into the program.cs to register it. Why not for example decorate all Handlers in your example with an attribute like [HandlerRoute("example/{name}")] and find all handlers by base class via reflection and take their attribute data to register. I often use annotations like this so that if I add a new handler I only add that one file that knows everything about itself and let the program.cs just auto detect everything. I dislike adding the actual thing and then in program.cs I need to explictly tell the system that I added it. A lot of program.cs (or if older Startup.cs) files I see are filled with like 100 service registrations etc.

    • @akzual50
      @akzual50 Před rokem

      Extension methods are what I use for that

  • @MrAKAQUAN
    @MrAKAQUAN Před rokem

    Thank Nick, the video is greate, but to be honest, I don't see much the benefit of using minimal API + Media vs traditional API controller + service layer. Could you help to explain? Thanks

    • @nickchapsas
      @nickchapsas  Před rokem +2

      Minimal APIs have a stripped down request flow. There is no such thing as validation middleware for example by default. You control the full flow and you opt into the feature you want so if I want validation I simply create a validator pipeline on top of this and I also validate my incoming items in a very clean way. The controller approach for validation is way clunkier and heavier. This is just a single example.

  • @andreasandersson7685
    @andreasandersson7685 Před rokem

    Hey Nick. It appears the properties inside a post requests becomes null. Are there any fix for this? :) Thanks for the video.
    //Edit: I removed [AsParameters] from MediatePost(), that solved the issue.

  • @danielegiovanetti9258

    Very special content from you. Thanks so much Nick. Does mediatR decrease response time performance?

    • @nickchapsas
      @nickchapsas  Před rokem +2

      Technically yes but realistically if your endpoint is doing any sort of work, form compute to network/db calls, it is extremely insignificant comparatively

    • @danielegiovanetti9258
      @danielegiovanetti9258 Před rokem

      @@nickchapsas thank you

  • @goremukin1
    @goremukin1 Před rokem +2

    Hi Nick! What is the benefit of using the Mediatr here? Why is this approach better than simple controllers?
    In case of controllers no need to register each end point in the Program.cs

    • @nickchapsas
      @nickchapsas  Před rokem

      There are benefits yes, I’ve answered this question in other comments

  • @mana20
    @mana20 Před rokem

    Is it hard to Unit Test using mediator? I know I ran into some issues with CAP handlers

    • @nickchapsas
      @nickchapsas  Před rokem +1

      I never had a problem unit testing it

    • @akzual50
      @akzual50 Před rokem +1

      I used SpecFlow for my BDD implementation. Test first development approach.
      Essentially what youve asked isn't even a question when you're test first.
      You build your behavior logic in behavior modules for the test scenarios first. Then you implement them into the service collection and call them with the provider.

  • @QuickZ_
    @QuickZ_ Před rokem

    uh oh sponsored by OD... What a plot twist.. I expect Microsoft vengeance in the next video. Azure devops cries can be heard through the web

  • @user-iv7uj7lx8n
    @user-iv7uj7lx8n Před rokem

    My main problem with MediatR (and the reason why I don't use it) is that it prevents me from easily navigating from the endpoint to the handler within Rider. If I use a service or just another method, I can navigate to it easily by ctrl+clicking the method call. With MediatR I'd need to search for the handler explicitly. Is there any smart way to get around this?

    • @jobumble8829
      @jobumble8829 Před rokem

      Put your Request and RequestHandler in the same file.. bingo... Navigate to requests..

    • @letifere
      @letifere Před rokem

      I do the same as Jo Bumble, put Handler and request objects in the same file.

  • @Tof__
    @Tof__ Před rokem +1

    I really dont know, so dont hate on me please, but why I would need to use MediatR, when Ardalis.Endpoints are just so much easier to setup and give the same benefits?

    • @nickchapsas
      @nickchapsas  Před rokem

      No judging here. Ardalis.Endpoints are built on top of Controllers which carry all the middleware and filters of said controllers and that request pipeline. Minimal APIs have a stripped down pipeline so you can use MediatR and add your own pipeline steps with MediaitR extension points, for example validation with fluent validation or logging/metrics. You basically control full flow

    • @Tof__
      @Tof__ Před rokem

      @@nickchapsas yeah, so if I understand correctly, that i shouldn't be bothered if I am not using minimal APIs

    • @nickchapsas
      @nickchapsas  Před rokem

      ​@@Tof__ I wouldn't say so. For example, I moved myself from Ardalis.Endpoints to Minimal APIs vs FastEndpoints because I think it's a way better approach. If you want a more performant approach with better feature support then you should be bothered, otherwise, you shouldn't

    • @steve-ardalis-smith
      @steve-ardalis-smith Před rokem

      @@nickchapsas I agree if you're moving to minimal APIs (which are the future) you should look at FastEndpoints which implements the same REPR pattern as Ardalis.Endpoints.

  • @ArinSinabian
    @ArinSinabian Před rokem

    What is better with this approach vs controller classes? For me this seems like you are creating controller classes with minimal api and mediatr.

    • @nickchapsas
      @nickchapsas  Před rokem +1

      What’s better is that you don’t violate single responsibility principle. Controllers can have many actions and many services injected in them with some of them not used by all actions. That’s bad. With controllers you also sign up for a bloated request pipeline with that you might not use but they will affect your performance. Here you have a simple and clean 1-1 relationship between endpoint and handler and you can opt into the features you want in a decoupled way with mediatr pielines

    • @ArinSinabian
      @ArinSinabian Před rokem

      @@nickchapsas yes totally understand now. Controller classes can become large.

  • @g_weaths
    @g_weaths Před rokem

    Nick great content as always, but i do find your content sometimes far too fast. If i had one request for you, it would be please slow down a little.

  • @dropsonic
    @dropsonic Před rokem +1

    It seems that you're reinventing the controllers with the help of MediatR :) Or am I getting it wrong?

    • @paleocomburo
      @paleocomburo Před rokem

      Had the same thought. Isn't this just an API controller, but via Mediatr?

    • @nickchapsas
      @nickchapsas  Před rokem

      You are getting it wrong indeed ;) Controllers can have N amount of actions and they are subject to a bloated implicit pipeline. This approach has a 1-1 relationship between endpoints and handling (single responsibility) and has the stripped down version of http handling allowing for a pluggable decoupled implementation of concerns via MediatR pipelines

  • @AngusMcIntyre
    @AngusMcIntyre Před 7 měsíci

    Why are we moving our endpoint code into multiple places yet _still_ bedding in HTTP concerns to the request handler? There is still place for good old domain mapping here. Or just use controllers. Thats what they are there for.

  • @souleater9189
    @souleater9189 Před rokem

    This'll be useful

  • @johnjosephsmith
    @johnjosephsmith Před rokem

    Where is the source code for this. Unless I’ve missed it I can’t find on GitHub etc

  • @lukaszluczko
    @lukaszluczko Před rokem

    Where can I find repo with this code?

    • @nickchapsas
      @nickchapsas  Před rokem

      The source code is available to my Patreons

  • @janvandenbaard5939
    @janvandenbaard5939 Před rokem +1

    Will this play nice with swagger?

    • @nickchapsas
      @nickchapsas  Před rokem

      Sure, just add the Produces extensions methods on the MediateXXX methods and it will be fine

    • @janvandenbaard5939
      @janvandenbaard5939 Před rokem

      I was thinking more about visibility of the parameters in swagger. I remember having some issues in NET 6 when binding query parameters to a model that they where no longer visible in swagger. Should have made myself clear. Sorry about that.
      I wil start setting up a test api in DOT NET 7 and test the stuff you show for myself :)
      Thanks for all your efforts. It is very much appreciated.

    • @Gobba61
      @Gobba61 Před rokem

      @@janvandenbaard5939 did you get the Params showing up in swagger?

    • @janvandenbaard5939
      @janvandenbaard5939 Před rokem +1

      @@Gobba61 I did but it was a cludge which i decided against. I created a model, implemented a BindAsync() method on the model in which i parsed the query parameters into the model. This also means that the query parameters should be declared in addition to the model itself in the endpoint configuration. It all worked but was so a recipe for disaster so we decided to just use the query parameters until .NET 7 is released.

  • @copycatzen
    @copycatzen Před rokem

    Isn't AddMediatR registered as scoped by default already?

  • @IgorChistruga
    @IgorChistruga Před rokem

    Hey Nick - is the sourcecode somewhere available?

    • @nickchapsas
      @nickchapsas  Před rokem

      It is. Check the first line in the description

  • @akzual50
    @akzual50 Před rokem

    Hey there Nick. I've discovered an approach to not using interfaces for DI.
    Basically the concrete class which could have its interface drawn from it isn't. Instead you give it mutable properties which a subservice would assign to.
    The end.
    This way you can unit test without fabricating mockups in reflection and instead explicitly set the mutable delegates and properties.
    Ideally your services won't have data type properties because you code for behavior, not data.

    • @richarddunning7459
      @richarddunning7459 Před rokem

      That means calling services are required to know what values to instantiate their dependencies with, e.g. if you're requiring your database access layer you will need to pass in fake credentials, rather than mocking out a valid response on a query request

    • @akzual50
      @akzual50 Před rokem

      @@richarddunning7459 not quite. The DAL would assign its executions to the Func variables in the adapter class. The adapter class will have high level methods that invoke those function calls.
      The DAL services will use the adapter class as a dependency to do the assignment and thats it

  • @Doctor.Livesey
    @Doctor.Livesey Před rokem

    what if request used several services to make result?

  • @realsk1992
    @realsk1992 Před rokem

    Is there an elegant way to do validation with MediatR, without throwing exceptions for the validation errors?

    • @nickchapsas
      @nickchapsas  Před rokem +1

      This one is. You simply puth your validation logic in the MediatR pipeline and return the IResult bad request diretly from there

  • @fatihcihanhizlikan1427

    That's Refit. 😀

  • @DarraghJones
    @DarraghJones Před rokem

    Isn't your weather forecast handler basically a weather forecast controller?

  • @adrian_franczak
    @adrian_franczak Před rokem

    What if I want send POST request with body?

    • @nickchapsas
      @nickchapsas  Před rokem

      Just add the object you wanna map in the request object and use it. The body will be automatically mapped to the object. You can also use the [FromBody] attribute to make it explicit

  • @vivekkaushik9508
    @vivekkaushik9508 Před rokem

    Honestly, I think its still complicated for any beginner or even an average c# sharp dev like myself. Even though it works perfectly and looks good but if I copy-pasted this boilerplate in my project, my team would ask me to justify it and I'm afraid I wouldn't do a great job doing that.
    What's wrong with cut-paste the implementation using Abstract classes? I haven't done this. Anyone any idea?

  • @adrian_franczak
    @adrian_franczak Před rokem

    what about fluent validation in this pipeline?

    • @nickchapsas
      @nickchapsas  Před rokem

      That's where the magic happens because now you can have FluentValidation as a MediatR pipeline on top of the handler which is way cleaner and it can be in just one place

  • @anthonylerouge9900
    @anthonylerouge9900 Před rokem

    It is interesting for simple apis but what if you need specific HttpStatus codes?
    Here you return only 200 but what about 400, 404, ... ?
    I guess you can kind of normalize the result of the mediator request to kind of be able to handle these types of status codes but still

    • @nickchapsas
      @nickchapsas  Před rokem

      The Results and TypedResults method contains all the statues you might need. Results.NotFound(), Results.BadRequest() etc

    • @anthonylerouge9900
      @anthonylerouge9900 Před rokem

      @@nickchapsas I mean, the extension method is generic, so how do you manage if this request needs to returns 404 and that request 400?

    • @anthonylerouge9900
      @anthonylerouge9900 Před rokem

      it works well with the happy path but what about error handling?

    • @nickchapsas
      @nickchapsas  Před rokem +1

      @@anthonylerouge9900 Like I said, you just handle the error in the handler and return the appropriate response.

  • @jairgza
    @jairgza Před rokem

    As far as I can see mediatr only knows about ExampleRequest, How mediator knows which handler instantiate and run ?

  • @amrosamy8232
    @amrosamy8232 Před rokem

    I'd prefer returning a concrete type instead of an abstract interface "IResult"
    It would be better for swagger documentation

    • @leonardoformaggi7614
      @leonardoformaggi7614 Před rokem +1

      You can use the .Produces() method overloads to generate your swagger appropriately.

    • @amrosamy8232
      @amrosamy8232 Před rokem

      I'd say returning Result can be an option as well.

    • @leonardoformaggi7614
      @leonardoformaggi7614 Před rokem

      It is. Although with Produces you can specify different responses for different status codes, if you need to. Whatever is best for you scenario.

  • @fehmianac
    @fehmianac Před rokem

    Hey Nick,
    I am wondering about Patch endpoint in Minimal API. Would you give some advice to me ?

  • @nofatchicks6
    @nofatchicks6 Před rokem +1

    I built the same thing in .net 6. It was a complete pain in the arse. .net 7 will put me out of a job 😅

  • @weluvmusicz
    @weluvmusicz Před rokem

    What about Swagger with this approach?

    • @nickchapsas
      @nickchapsas  Před rokem +1

      You'd have to add the fluent extensions "Produces" on the MediateXXX calls to describe the endpoint's responses

  • @dmisterb
    @dmisterb Před rokem

    Hey Nick! Could you make some videos about System.Reactive?

    • @nickchapsas
      @nickchapsas  Před rokem +1

      I have one coming in September or October

  • @AizenSousuke92
    @AizenSousuke92 Před rokem

    anyone tried this in docker and it works?

  • @manni.Net60
    @manni.Net60 Před rokem

    Isnt this becoming closer and closer to Controllers every Time?

    • @nickchapsas
      @nickchapsas  Před rokem

      You can handle multiple requests in a single controller violating single responsibility. This is a better structure

    • @PelFox
      @PelFox Před rokem

      @@nickchapsas You could create one controller per request if you want. You are not forced to put all action methods in the same controller.
      With VSA you could do one GetAllCustomersController paired with MediatR request/handler.

    • @nickchapsas
      @nickchapsas  Před rokem

      @@PelFox Yeah at that point why are you using a controller in the first place? Why would you use a grouped routing construct and limit it to one action, and one that comes with a lot of implicitly bloated request pipeline on top of that

    • @PelFox
      @PelFox Před rokem

      @@nickchapsas Never said it was good, just said it is possible. Nothing forces you to add multiple action methods in a controller.

  • @pcapcapca
    @pcapcapca Před rokem +6

    I'm disappointed with that age of 60

  • @roko567
    @roko567 Před rokem

    I have yet to see a single good reason to go "cleaner" than the MVC patttern

  • @BryonLape
    @BryonLape Před rokem

    Spring allowed a simpler and cleaner version of this over 20 years ago. Still too much boilerplate code for things that are not necessary.