The Smart Way of Using the Decorator Pattern in C#

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everybody I'm Nick and this video I'm going to show you how you can add Behavior into your existing classes in c-sharp without touching them at all I'm going to show you some code and I'm going to leave that code as it is and everything we do around it is what will add that behavior now this has actually been possible for years and we've kind of seen it before in this channel however in this video I'm going to show you how you can do it without any dependencies and because.net 8 adds a very special feature I found a way to use that feature in this concept to make it even cleaner if you learned of content and you want to see more make you subscribe for more training check out my courses on dumbtrain.com now quick announcement before I move on we have a brand new cost on Dom train called getting started with the main driven design that has been one of the most requested topics for courses on dome train and is finally here and is offered by the excellent educator and content creator ambikai Mountain band and in case you don't know amikai has his own YouTube channel Link in the description give him a sub but he's also a software engineer in Microsoft whose code Powers Technologies behind things like Microsoft Office so literally hundreds of millions of users a month use the stuff he writes he's an expert on the topic and he actually runs training like that in Microsoft as well so you're getting the highest quality possible which is what I wanted to offer with Dome train in the first place now to celebrate the launch I'd like to offer the first 500 of you a 20 discount code on the course so use code ddd20 at checkout to claim it and trust me when I say these do go quick so if you want to buy it buy it now also if you buy this getting started the course you will also get a special discount code when the Deep dive and advanced versions of this DVD course around so you can double dip in discounts all right enough with that back to the video okay so let me show what I have here have a simple api.net 8 API it doesn't really have anything and it is sort of a weather API but it's using a real Weather Service so what I'm doing here is I have an HTTP client I have an iweather service and then I have a weather endpoint I'm getting a city and I'm getting the current weather for a city so if I go ahead and I just quickly run this I have a request here on Postman so we're going to go ahead and open it up and if I say give me the weather for London as you can see we're getting the weather for London if I say row I'm gonna get Rome and so on and so forth and all that actually goes to a real API behind the scenes as you can see the open weather map API and that is what is giving me the weather and you can see all that code over here very simply we're using the HTTP client Factory we are calling that weather API and then getting back the weather and returning it now the behavior we want to add is actually here and it has to do in this case with resilience because what happens if that service has a transient issue and for some reason it throws an exception or it just doesn't work but we just want to retry for like an amount of times afterwards to hopefully try to get a response and maybe let's do that for like three times now I'm not going to use the nuget package poly to add this retry policy because it's very simple I don't want to do that but more importantly I don't want to add it directly here now one thing I should point out is that if you're using poly you can actually bake the retry policy in your HD to be client Factory I know that's a possibility we're going to ignore that because I want to give you a generic solution for any type of problem this is just one of those examples now should the retry policy live directly here in my opinion no this service should only know how to get the weather from the open weather map API and just return it into something that I want to use in my service so you wouldn't really add the retry policy directly here what you do is you would have that in a different place and how would you do that well one way to do this is by creating a separate weather map service so you can say resilient Weather Service now this service doesn't know anything about upper weather map API or the specific implementation all it knows is that it can get the weather some way and we're gonna see how now the biggest mistake many people do when they try to do this sort of thing is actually extend the existing implementation so say open Weather Service and then override the methods and try to do it this way my opinion this is a very very idea because you're tying this into your open Weather Service which at this point you might as well just smush them together doesn't really make a difference you made a mess anyway so what I like to do is actually create that resilient service and implement the interface the same interface that the open weather map service also implements so completely agnostic of implementation and I'm going to go ahead and just implement the one method I'm missing and that is it now ultimately my goal here is to use the real open weather map service and have all of my retry logic here how can I do that well let's just write some very very basic retry logic so first I'm going to say catch any exception here and you can be more specific and only retry exceptions that you think can be retried physically but for this example I'm just gonna go the stupid way and I'm going to say retry count equals zero for example now if we do have an exception we can have a check that says that if we try count is less or equal or just less depending on how you want to approach it like four or five then we try count plus plus and retry it the way I'm going to retry It Is by actually having a start label here and saying go to start yes you can do this with a loop and yes you probably shouldn't use labels and go to's but it's easier for me to read for this example and probably for the viewer as well because you can just follow the flow like this so that's why I'm doing it in your own applications do whatever you want and I'm gonna say throw in the end and now in the try section I want to use a real service how do I do that well I do that by actually and that's very interesting injecting the interface so I'm still not really tied to the implementation here I'm just going to say inject it and then all I'm gonna do here is say return a weight and then Weather Service and that is it and I know this probably looks very weird to you but what we're trying to achieve here is to have this resilient Weather Service effectively decorate the real service so the goal is that every time we resolve the iweather service because it's just an interface we don't really know the implementation all it's really going to happen behind the scenes is go from Weather Service to resilient Weather Service to open Weather Service and this is what will be returned here this will all make more sense as we go into the flow now how would you do that before.net Aid well it's actually pretty simple currently the only thing you need to register is this Singleton and then you say iweather service and then open weather map service but if you want to do the resilient redirection what you want to do is first say Builders Services Dot and Singleton and register the open weather map service on its own which can be a bit tricky but that's how it looks and then to register the real iweather service through the resilient one you want to say builder.services.add Singleton I wear the service and then use the get required service over here to get the open weather map service but all that and that's where the tricky thing is and how to follow is wrapped around the resilient Weather Service so what's happening is when you resolve the Iowa the service what's going to happen is you're gonna create a resilient one and you're gonna resolve through the DI container the open weather map service so the two redirections type of thing and if I do that I'm going to take a few breakpoints here and also the open weather map service and the resilient one over here and you're going to see exactly what's going on so let's go ahead and just debug this and try to resolve the weather for some city so let's go to post one call for Rome and what do we hit first well of course we hit the weather endpoint and we have the Weather Service which as you can see by the type here it's the resilient Weather Service but this is all abstracted away so it's the decorated version we're resolving here and if I go into that you're going to see that the one I'm resolving in the Constructor is the open where the map save is the real one so I can just have everything here and then through the retry sort of wrapper or decoration I go into the real one I get the weather I return it and happy days I have the weather back now arguably this is a bit of a convoluted solution but that's how you do this until.net 7. if you did not use a library like scooter which sort of simplifies that and that would be fine however I found out a way to actually greatly simplify this in.net a so to show you how I'll do that I'm just going to go ahead and comment everything out now I had a few pet peeves with this implementation namely you have to register the open weather map service on its own which I'm not a fan of because if you want to get a non-decorated version then how do you it was all a bit weird so what you can do now in dot at 8 is you can use the kid services to redirect things so what you can do is say build that service is not at Singleton and I can register the iweather service and the original thing behind the scenes which is the open weather map service however the one change I have to make is I want to turn this into a kid Singleton so a Singleton which has a special key in this case I'm just gonna say OG as original service and then what I'm going to do is say add Singleton eyewear the service resilient Weather Service and that's all I'm going to have in my program.cs the rest will happen in resilient Weather Service because what I want to do is just resolve this through the key so I'm going to say from kit Services OG and I'm going to get the OG service which is if you remember the weather map service so if I need the decorated one I don't need to specify a key if I need the OG one I can specify a key and I'm leveraging that to resolve it in here so now if I run the application again Watch What Happens I'm going to go back here call the endpoint and as you're going to see I still have the same resilient Weather Service being resolved here as the type and when I go in you're going to see I have the open weather map service and I'm getting the weather as expected and all that way simpler by using the kit services and the last thing I want to show you is how we can actually make it even simpler by just creating a simple extension method the goal of that is to just make it very usable because ultimately you want to be able to say for example builder.services.add decorated Singleton for example and then say something like from iweather service I want to have the correction which is the resilient Weather Service and then from that I want to go to the open weather map service which is the real service so I want to have something like this as my experience how can I do that well I'm going to go ahead and just comment this one out and create a new extensions class so let's go ahead and do that turn this into static and I'm going to add a method so it's going to be and add decorated Singleton in this case and I have the T service the T decorated one or the one that I'm going to decorate with and then the T final one basically the destination so once I have all that I can say this I service collection say Services over here and then I can have also a key because I think I'm going to need that the same way I had before the implementation will look like this so from service to final and from service to decoration the file has the key same thing I had in the program.cs but now here in a generic way now for this all to work I need some restrictions so this needs to be a class listen should be a class it needs to be an implementation of the service as well so with all that here this compiles and I can go back to program.cs and have the add decorated Singleton and I can give it the same over here OG key and now I say add decorated Singleton from my Weather Service to resilient from resilient to open Weather Service and add that behavior externally without touching my class I if I do all that now as you're going to see if I go to postman call that again same behavior as before so I have the resilient service over here I go in here I get the open weather map service and then I do my stuff and I return the weather back so is this so simple you can now decorate your classes in a way way nicer way you don't have to bring an external package and it's very generic and very nice especially with a key service that just got at it I'm really curious to see what else I can do with kit Services because the flexibility they allow especially if you're building a library is actually amazing but for now that's what I have for you and I really really want to know in the comments down below what do you think about this how are you doing decoration and is that something you would use leave a comment down below and let me know well that's all thank you very much for watching as always keep coding
Info
Channel: Nick Chapsas
Views: 66,373
Rating: undefined out of 5
Keywords: Elfocrash, elfo, coding, .netcore, dot net, core, C#, how to code, tutorial, development, software engineering, microsoft, microsoft mvp, .net core, nick chapsas, chapsas, dotnet, .net, .net 8, decoration c#, c# scrutor, scrutor, scrutor decoration, .net decoration, .net decorate, keyed services, dependency injection
Id: KxE7VK3Mj6g
Channel Id: undefined
Length: 12min 37sec (757 seconds)
Published: Thu Aug 31 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.