Write cleaner APIs in .NET 7 with MediatR

Поделиться
HTML-код
  • Опубликовано: 29 сен 2024
  • 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/ChapsasG...
    Follow me on Twitter: bit.ly/ChapsasT...
    Connect on LinkedIn: bit.ly/ChapsasL...
    Keep coding merch: keepcoding.shop
    #csharp #dotnet #dotnet7

Комментарии • 243

  • @nickchapsas
    @nickchapsas  2 года назад +302

    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 2 года назад +1

      wait what? :D

    • @barloc2
      @barloc2 2 года назад +14

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

    • @pdevito
      @pdevito 2 года назад +4

      Ruined

    • @redouane5626
      @redouane5626 2 года назад +14

      you should apalogize for naming it MinimalatR 😑

    • @dungimon1912
      @dungimon1912 2 года назад +1

      huh?

  • @victor_pogor
    @victor_pogor 2 года назад +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  2 года назад +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 2 года назад

      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  2 года назад +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 2 года назад +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
    ));
    }

  • @AyahuascaCeremony
    @AyahuascaCeremony 2 года назад

    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  2 года назад +4

      I will be making a video on that topic indeed

  • @andrewalexopoulos921
    @andrewalexopoulos921 2 года назад

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

  • @diligencehumility6971
    @diligencehumility6971 2 года назад

    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

  • @daxyhrgaming5292
    @daxyhrgaming5292 2 года назад

    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  2 года назад

      You wouldn’t combine this with ValueOf

  • @user-iv7uj7lx8n
    @user-iv7uj7lx8n 2 года назад

    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 2 года назад

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

    • @letifere
      @letifere 2 года назад

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

  • @bad-at-art-games
    @bad-at-art-games 2 года назад

    Isnt this becoming closer and closer to Controllers every Time?

    • @nickchapsas
      @nickchapsas  2 года назад

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

    • @PelFox
      @PelFox 2 года назад

      @@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  2 года назад

      @@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 2 года назад

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

  • @barloc2
    @barloc2 2 года назад +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  2 года назад +22

      I MISS CLICKED THE BUTTON DON'T JUDGE ME

  • @qwer1234cvb
    @qwer1234cvb 2 года назад +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.

  • @buriedstpatrick2294
    @buriedstpatrick2294 2 года назад +23

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

    • @Suriprofz
      @Suriprofz 2 года назад +3

      And make them immutable.

    • @aj.arunkumar
      @aj.arunkumar 6 месяцев назад

      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 ?

  • @jamesmussett
    @jamesmussett 2 года назад +12

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

    • @nickchapsas
      @nickchapsas  2 года назад +5

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

    • @sergiik2168
      @sergiik2168 2 года назад +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 2 года назад +1

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

    • @Gobba61
      @Gobba61 Год назад

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

  • @benjamincharlton3774
    @benjamincharlton3774 2 года назад +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 2 года назад

      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.

  • @Dimich1993
    @Dimich1993 2 года назад +1

    I cannot read MinimalatR correctly either. :D
    Please support Ukraine guys!

  • @digitalhome6575
    @digitalhome6575 2 года назад +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 :)

  • @nocgod
    @nocgod 2 года назад +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)

  • @pcapcapca
    @pcapcapca 2 года назад +6

    I'm disappointed with that age of 60

  • @CarmenSantiNova
    @CarmenSantiNova 2 года назад +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.

  • @brud90
    @brud90 2 года назад +1

    hmmmm... It looks like F# and Giraffe 😉

  • @AngusMcIntyre
    @AngusMcIntyre 10 месяцев назад

    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.

  • @harbor.boundary.flight
    @harbor.boundary.flight 2 года назад +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 😅

  • @HakunaMatata225
    @HakunaMatata225 6 месяцев назад

    still understand whats the point of using MediatR or what problem it solved!! you could had done this without MediatR !!!

  • @fred.flintstone4099
    @fred.flintstone4099 Год назад

    This is pretty dumb. You can test minimal API, not with unit tests but with integration tests. What you did with using MediatR and implementing handlers is basically just like implement a controller but with more boilerplate code and dependencies, so this is pretty silly, it is much better to just create controllers.

  • @SamueleFurnari
    @SamueleFurnari 2 года назад +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! 💪

  • @amantinband
    @amantinband 2 года назад +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  2 года назад +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 2 года назад +1

      @@nickchapsas there is also the HttpContextAccessor as well

  • @VijayKumar-wy9ku
    @VijayKumar-wy9ku 10 месяцев назад

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

  • @g_weaths
    @g_weaths Год назад

    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.

  • @Suriprofz
    @Suriprofz 2 года назад

    minimal api seems so hackish, like it's added only to allow more node(express) developers te join microsoft here..

  • @BryonLape
    @BryonLape Год назад

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

  • @GleichCraft
    @GleichCraft 2 года назад +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  2 года назад +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

  • @ja-rek8846
    @ja-rek8846 Год назад

    Why people so love to have a god object in they project as madiatR?

  • @karthiksrivatsa8243
    @karthiksrivatsa8243 2 года назад +1

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

  • @FraserMcLean81
    @FraserMcLean81 2 года назад +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.

  • @kippie86
    @kippie86 2 года назад +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  2 года назад +3

      All [FromXXX] attributes work inside the request

  • @bryanlewis3643
    @bryanlewis3643 2 года назад +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  2 года назад +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

  • @jonholt8429
    @jonholt8429 2 года назад +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 2 года назад

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

  • @metaltyphoon
    @metaltyphoon 2 года назад +1

    At 1:55 you said "that's not really testable" why is that? If you business logic is just used in via an API, then why can't you just use WAF? The hole video boils down to allowing you to do "easier" testing from whatever handler goes inside `app.MapGet` and not much more while introduction extra libraries.
    Minimal APIs is a nice break from controllers and align more with flask / express / golang. It's a breath of fresh air and now we are just going to bloat it again?

    • @nickchapsas
      @nickchapsas  2 года назад

      WAF is used for integration testing. I should have said that it's not "unit testable". The video isn't about testing though. It is about structure. It is way cleaner to have your request's handling logic in a single specialized class that does that thing only and it helps with code organization.

    • @metaltyphoon
      @metaltyphoon 2 года назад

      @@nickchapsas I understand the video is not about testing but about structure. You can still get that the structure you had without introducing mediatr right?

  • @idzyubin720
    @idzyubin720 2 года назад +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 2 года назад +1

      Nick already talked about the performance of MediatR in this video: ruclips.net/video/baiH3f_TFfY/видео.html

    • @idzyubin720
      @idzyubin720 2 года назад

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

  • @georgepagotelis
    @georgepagotelis Год назад

    I couldn't attach EndpointRouteBuilderExtensions methods such as WithTags, etc. Example:
    app.MediatrGet2("test/AsParameter/{name}")
    .WithTags("*MediatR")
    .WithOpenApi();
    So over my lunchtime, I changed the method so it would. Have I mistaken something as dropping off EndpointRouteBuilderExtensions has those methods but WebApplication doesn't.
    public static class MediatrExtensions {
    //public static WebApplication MediatrGet(this WebApplication app, string template) where TRequest : IHttpRequest {
    public static IEndpointConventionBuilder MediatrGet2(this IEndpointRouteBuilder endpoints, string pattern) where TRequest : IHttpRequest {
    return endpoints.MapGet(pattern, async (IMediator mediator, [AsParameters] TRequest request) => await mediator.Send(request));
    }
    }

  • @sergiik2168
    @sergiik2168 2 года назад

    So handlers doesn't contain business logic and these are more like proxies to business layer. And what is the point to add additional proxy-layer, when instead of this you could directly call services from MapRoute methods? This looks like over-engineering.

  • @andreasandersson7685
    @andreasandersson7685 2 года назад

    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.

  • @jairgza
    @jairgza 2 года назад

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

  • @vivekkaushik9508
    @vivekkaushik9508 2 года назад

    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?

  • @QuickZ_
    @QuickZ_ 2 года назад

    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

  • @AizenSousuke92
    @AizenSousuke92 Год назад

    anyone tried this in docker and it works?

  • @samsonquaye9913
    @samsonquaye9913 Год назад

    How do we handle post?

  • @dropsonic
    @dropsonic 2 года назад +1

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

    • @paleocomburo
      @paleocomburo 2 года назад

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

    • @nickchapsas
      @nickchapsas  2 года назад

      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

  • @fatihcihanhizlikan1427
    @fatihcihanhizlikan1427 2 года назад

    That's Refit. 😀

  • @jonathanperis3600
    @jonathanperis3600 2 года назад

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

  • @cmartinez4727
    @cmartinez4727 2 года назад

    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?

  • @Tof__
    @Tof__ 2 года назад +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  2 года назад

      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__ 2 года назад

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

    • @nickchapsas
      @nickchapsas  2 года назад

      ​@@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 Год назад

      @@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.

  • @endmrx
    @endmrx 2 года назад

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

  • @RuslanSafroniuk
    @RuslanSafroniuk Год назад

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

  • @johnjosephsmith
    @johnjosephsmith Год назад

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

  • @wojciechwilimowski985
    @wojciechwilimowski985 Год назад

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

  • @VinayKumar-ki5fd
    @VinayKumar-ki5fd 2 года назад

    Very gooood :)

  • @JonathanPeel
    @JonathanPeel 2 года назад

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

  • @StigBrembo
    @StigBrembo 2 года назад

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

  • @bernardo44250
    @bernardo44250 2 года назад

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

  • @michaelfernandes6893
    @michaelfernandes6893 2 года назад

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

  • @kasperkadzielawa8658
    @kasperkadzielawa8658 2 года назад

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

  • @scottatkinson7083
    @scottatkinson7083 2 года назад

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

  • @taufikdev88
    @taufikdev88 Год назад

    love the way you create an extensions class for registering everything

  • @antonmartyniuk
    @antonmartyniuk 2 года назад

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

  • @paulward8087
    @paulward8087 2 года назад

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

  • @roko567
    @roko567 2 года назад

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

  • @gileee
    @gileee 2 года назад

    I created something very similar in my learning demo project. Basically all endpoints are individual classes that inherit an IEndpoint interface (which are all auto injected), the interface has a "GetHandler()" method which returns a delegate (which the app.MapGet accept anyway). All my endpoints now look like:
    public class ExampleEndpoint: IEndpoint {
    public Delegate GetHandler() =>
    ([FromBody] MyRequest req, [FromQuery] int some, CancelationToken ct....) =>
    ... do endpoint logic
    }
    I extended it so that I have an AbstractEndpoint class that inherits IEndpoint and takes HTTP metod type (GET, POST...), the route pattern in the constructor and has a Map() method which can be overridden if your endpoint has some extra info like Produces().... and stuff like that.

    • @pilotboba
      @pilotboba 2 года назад

      Sounds like ardalis' endpoints project (which uses controllers under the hood)

  • @Arkensor
    @Arkensor 2 года назад

    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 2 года назад

      Extension methods are what I use for that

  • @DevonLehmanJ
    @DevonLehmanJ 2 года назад +1

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

    • @EternalVids
      @EternalVids 2 года назад

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

    • @DevonLehmanJ
      @DevonLehmanJ 2 года назад

      @@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 2 года назад

      @@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 2 года назад +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.

  • @janvandenbaard5939
    @janvandenbaard5939 2 года назад +1

    Will this play nice with swagger?

    • @nickchapsas
      @nickchapsas  2 года назад

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

    • @janvandenbaard5939
      @janvandenbaard5939 2 года назад

      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 Год назад

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

    • @janvandenbaard5939
      @janvandenbaard5939 Год назад +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.

  • @Velociapcior
    @Velociapcior 2 года назад

    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 2 года назад

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

  • @MrAKAQUAN
    @MrAKAQUAN 2 года назад

    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  2 года назад +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.

  • @realsk1992
    @realsk1992 2 года назад

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

    • @nickchapsas
      @nickchapsas  2 года назад +1

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

  • @rade6063
    @rade6063 2 года назад

    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  2 года назад +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

  • @pablocom
    @pablocom 2 года назад

    Loving this new .NET 7 feature

  •  2 года назад

    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  2 года назад +2

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

  • @maacpiash
    @maacpiash 2 года назад

    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  2 года назад

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

  • @thespicycoder5583
    @thespicycoder5583 2 года назад

    Nick, can you please do a mini series on Dapr

  • @spirits_
    @spirits_ 2 года назад

    I recommend you never use MediatR for anything

  • @ADSNGreenLife
    @ADSNGreenLife 2 года назад

    Nick you are dam good man!! bravo

  • @framidox3757
    @framidox3757 2 года назад

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

  • @tonongah102
    @tonongah102 2 года назад

    Thanks bro that was really helpful

  • @adrian_franczak
    @adrian_franczak 2 года назад

    What if I want send POST request with body?

    • @nickchapsas
      @nickchapsas  2 года назад

      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

  • @DarraghJones
    @DarraghJones 2 года назад

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

    • @nickchapsas
      @nickchapsas  2 года назад

      No it is a single controller action

  • @miindgame
    @miindgame 2 года назад

    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  2 года назад

      One handelr per request not one handler for all requests

    • @miindgame
      @miindgame 2 года назад

      @@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! :)

  • @copycatzen
    @copycatzen 2 года назад

    Isn't AddMediatR registered as scoped by default already?

    • @nickchapsas
      @nickchapsas  2 года назад +1

      Pretty sure it’s transient

  • @xian9029
    @xian9029 2 года назад

    Very helpful..thanks a lot.

  • @IgorChistruga
    @IgorChistruga Год назад

    Hey Nick - is the sourcecode somewhere available?

    • @nickchapsas
      @nickchapsas  Год назад

      It is. Check the first line in the description

  • @Mikebutawski
    @Mikebutawski 2 года назад

    This was just awesome! Thanks a lot!

  • @volodymyrliashenko1024
    @volodymyrliashenko1024 2 года назад

    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 2 года назад

      There's always eShopOnContainers.

    • @suleymanov1990
      @suleymanov1990 2 года назад

      Also CleanArchitecture template and NorthwindWindTraders from Jason Tyler.

  • @ArinSinabian
    @ArinSinabian 2 года назад

    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  2 года назад +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 2 года назад

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

  • @bjarkeistruppedersen8213
    @bjarkeistruppedersen8213 2 года назад

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

    • @nickchapsas
      @nickchapsas  2 года назад +1

      Yeah can't see why that might be a problem

  • @jercyshore
    @jercyshore 2 года назад

    Java has left the channel

  • @isnakolah
    @isnakolah 2 года назад

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

    • @nickchapsas
      @nickchapsas  2 года назад

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

    • @isnakolah
      @isnakolah 2 года назад

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

  • @stevehoff
    @stevehoff 2 года назад

    Hmmm not to be that guy, but model binding isn't exactly a radical new idea.

    • @nickchapsas
      @nickchapsas  2 года назад

      You are that guy Steve

    • @stevehoff
      @stevehoff 2 года назад

      @@nickchapsas lol so I've been told.

  • @mana20
    @mana20 2 года назад

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

    • @nickchapsas
      @nickchapsas  2 года назад +1

      I never had a problem unit testing it

    • @akzual50
      @akzual50 2 года назад +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.

  • @adrian_franczak
    @adrian_franczak 2 года назад

    what about fluent validation in this pipeline?

    • @nickchapsas
      @nickchapsas  2 года назад

      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

  • @Doctor.Livesey
    @Doctor.Livesey 2 года назад

    what if request used several services to make result?

    • @nickchapsas
      @nickchapsas  2 года назад

      No problem at all. Most services do

  • @amrosamy8232
    @amrosamy8232 2 года назад

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

    • @leonardoformaggi7614
      @leonardoformaggi7614 2 года назад +1

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

    • @amrosamy8232
      @amrosamy8232 2 года назад

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

    • @leonardoformaggi7614
      @leonardoformaggi7614 2 года назад

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