The Smart Way of Using the Decorator Pattern in C#

Sdílet
Vložit
  • čas přidán 30. 08. 2023
  • Use code DDD20 and get 20% off the brand new Domain-Driven Design course on Dometrain: dometrain.com/course/getting-...
    Get the source code: mailchi.mp/dometrain/z8d6n6wtuk
    Become a Patreon and get special perks: / nickchapsas
    Hello, everybody, I'm Nick, and in this video, I will show you how you can change your code's behaviour without changing the code directly. We will be using a technique called Decoration and we will also use a new .NET 8 feature to make it even more interesting.
    Subscribe to Amichai: @amantinband
    Workshops: bit.ly/nickworkshops
    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

Komentáře • 139

  • @hoolio94
    @hoolio94 Před 9 měsíci +298

    I don't like it. The main disadvantage is that the decorator must know what it is decorating (by specifying a key to a 'FromKeyedServicesAttribute'). What if we want to have multiple implementations of some interface and all of them must be decorated in the same way? In my opinion it is indirect dependency by a string key. Technically it does not differ from extending a class instead of implementing the same interface and it's even worse because the dependency is hidden in a parameter of some attribute.

    • @IceQub3
      @IceQub3 Před 9 měsíci +11

      This

    • @orterves
      @orterves Před 9 měsíci +5

      I believe the key belongs to and should be defined within the decorator. So it doesn't know what it is decorating, it just creates a requirement that something must be keyed with its key in order for the decorator to be used.
      Multiple different decorators of the same interface all define their own unique keys (I suggest a public const guid string). Then in the bindings you'd choose which decorator implementation and use its key for the keyedsingleton
      You're right that specifying the key outside of the decorator is not really much different to injecting the implementation itself. I think not defining the key string within the decorator class is a major oversight by this video

    • @NickSteffen
      @NickSteffen Před 9 měsíci +6

      Yea, I don’t really see an issue with the first DI syntax. I think it quite succinctly describes what is happening. If your trying to constrain the object your decorating you should really do that through interfaces.

    • @neilbroomfield3080
      @neilbroomfield3080 Před 9 měsíci +4

      Yes, I was thinking the same I'm sure this must violate at least one (I..e Liskov), if not more, of the SOLID principles.

    • @MrReniuz
      @MrReniuz Před 9 měsíci +6

      I agree with all of you. IMHO readability is way better in the first example. Dependency injection by magic string sound error prone way to do it.

  • @deesmon2084
    @deesmon2084 Před 9 měsíci +24

    I don't like the key approach with the decorator owning the key. It would rapidly become a mess with multiple level of decorator.

  • @CameronOwen101
    @CameronOwen101 Před 9 měsíci +17

    This is a bit like Inception, except you never go more than 1 level. Any deeper is a path to madness...

  • @andersborum9267
    @andersborum9267 Před 9 měsíci +12

    It's coupling the composition root with the implementation; much better to use named registrations and in turn register the decorator using a factory delegate (that in turn resolves the named registration). Regardless, the decorator pattern is one of the most productive and important patterns in modern API development.

    • @berzurkfury
      @berzurkfury Před 7 měsíci +1

      this is the comment i was looking for. im also not a fan of needing to bake in anything DI related to any classes or interfaces. anyone could switch to autoFac or lamar, etc and now what registrations are broken

  • @MrJeffrey56
    @MrJeffrey56 Před 9 měsíci +1

    I have watched most of your videos. I am not sure that I agree with the philosophy of this but the idea to do it this way is brilliant. Keep it up.

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

    This was very cool. I always learn something. I will try this out today. Thanks Nick.

  • @GuidoSmeets385
    @GuidoSmeets385 Před 9 měsíci +13

    I really dislike the way you hook up the decorated service in the implementation. That breaks the whole idea of having your application composition separate from your implementation.
    You're better off putting that in your extension method, resolve the og there. But you can't really do that with the vanilla DI framework, because your factory needs to be aware of all the parameters while most of the time your decorator will want some other constructor parameters too.

  • @markovcd
    @markovcd Před 9 měsíci +43

    This api doesn't really work well with decorator pattern since it supports only one level of decoration. The whole point of decorator is that you can stack as many of them as you want.
    Edit: I have an idea:
    services.Decorate()
    .With()
    .ThenWith()
    .ThenWith();

    • @finickyflame
      @finickyflame Před 9 měsíci +14

      It's better to use scrutor at that point

    • @emmanuelrobles2124
      @emmanuelrobles2124 Před 9 měsíci +3

      there is a lib that does that, Scrutor

    • @emmanuelrobles2124
      @emmanuelrobles2124 Před 9 měsíci +1

      @@finickyflame ups, i didnt see this

    • @khellang
      @khellang Před 9 měsíci +5

      I approve of this message 😜👍

    • @markovcd
      @markovcd Před 9 měsíci +1

      @@khellang I think you might be a little bit biased ;)

  • @petewarner1077
    @petewarner1077 Před 9 měsíci +4

    Decorators = method interception = pipelines = all good. I don't buy the developer confusion argument against decorators, I think the problem can be overcome with structuring and awareness of configured behaviors.
    What I don't like about this example is the fixed key that the decorator needs to know, which limits the decorator to a single depth because of a dependency on the original/core implementation.
    Decorators as behavioral extension points should be capable of arbitrary depth.

    • @nickchapsas
      @nickchapsas  Před 9 měsíci +1

      You can always calculate a key based on the redirection flow so compose a string that is IWeatherService-Resilient-OpenWeatherMap. This is just an example of the approach. You can take it and adapt it to whatever you want

  • @KangasniemiJerri
    @KangasniemiJerri Před 8 měsíci +3

    5:09 - For anyone even considering using labels like that, instead just use a do-while with a break condition.

    • @rex.mingla
      @rex.mingla Před 5 měsíci

      Or just a for loop with a return. I didn’t even know about labels in c# 😅

  • @youcefmerzoug3763
    @youcefmerzoug3763 Před 8 měsíci +1

    Great video. The main issue is coupling introduced by the key which kills the idea of decoration as you're now tight to a single implementation. I believe keeping it explicit in the DI registration or using a factory is better

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

    Nice, thanks for video!

  • @hnz8250
    @hnz8250 Před 9 měsíci +3

    Seems to me that Factory Pattern is also a fit solution for resolving dependencies of a decorated service like this. Correct me if I'm wrong. I'm still learning design patterns and those are really great to use :D

  • @diego_samano
    @diego_samano Před 8 měsíci

    Amazing video. I have a suggestion to even avoid 2 issues with this approach:
    1. To avoid using hardcoded keys to be passed in the registration, we can add a static Key property in the Interface. This will allow to pass the Key property instead.
    i.e. services.AddDecoratedSingleton(MyService.Key), something like that.
    2. To avoid boxing, why not using generics. In this case the Interface may be of type generic, so the Key property I mentioned before may be of type K.

  • @AmateurSpecialist
    @AmateurSpecialist Před 8 měsíci +1

    My preferred decorator pattern involves using DispatchProxy. That way I can (e.g.) wrap all calls in an exception logger, or timing, or security without having to implement all the interfaces I want to decorate. It will handle any method on the interface using it automatically. The hardest part if elegantly registering it all (still working on that aspect of it).
    I'm sure that since it's using reflection, it's not the fastest, but the laziness aspect really pays off.

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

    Great video Nick. In my case, i believe in this specific situation is better two importations of same interface with the common code in an abstract class. Of course for this is required skip the restriction of do not modify the weather service 😂

  • @harisuru
    @harisuru Před 9 měsíci +2

    I guess the example here is little hard to digest. I can see one useful scenario while api versioning(for V1 i can have one implementation and for V2 i can have different implementation). Thanks for sharing it :)

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

    What about using generics instead of string keys...? So the IService will have a IService which gets registered to the actual implementation, then your IService can be registered with your "root entry" actual implementation. There can be many variations using this pattern

  • @stevenodlum4563
    @stevenodlum4563 Před 9 měsíci +1

    This seems like it would be good for logging, retries, audit trails, and other non critical pieces of functionality. I wouldn't expect this type of approach would necessarily be useful or even ideal for business logic. As you pointed out, the main service should really only know how to do it's main job and the rest of the fluff can be moved elsewhere and this approach could work for that. I think it may get a little out of control if you have multiple different kinds of fluff that need to be removed. Logging would need it's own layer, retries their own layer, caching, etc... The more fluff you have, the more layers you have which can just make the code much harder to understand I think.

  • @leandrowitzke6405
    @leandrowitzke6405 Před 9 měsíci +25

    I'm not sure when is good to have the decorator pattern, and when is not. Recently I begin to work on an new company where they were using the Decorator Pattern for translations where basically are 5 layers to find translations (custom -> providers -> another providers -> etc) and was really hard to debug and understand completely the code. For this kind of escenarios such as retry policies or cache layer I think is ok.

    • @vasyltravin1006
      @vasyltravin1006 Před 9 měsíci +7

      At my team we use decorators when we want to enhance logic of libraries/frameworks. Since most of them use dependency injection, it’s easy to add your own code to the one you don’t have control over.

    • @Denominus
      @Denominus Před 9 měsíci +5

      You’ve touched on a downside of decorators. If you get too carried away with them, they can obfuscate code. Not that surprising, getting carried away with patterns/abstractions almost always leads to a poor cost to benefit trade off.
      Generally, you want to reserve them for cross cutting “operational” concerns and not have them too heavily nested. They normally aren’t a good fit for business logic.

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

      Sounds like decorators were used where they shouldn't be used.
      But for stuff like cross cutting concerns like logging it's actually a nice pattern to apply l

    • @jfpinero
      @jfpinero Před 9 měsíci +2

      We decorate classes for caching using Scrutor decorator attribute.

    • @jonathansaindon788
      @jonathansaindon788 Před 8 měsíci

      Decorator pattern is very useful on food order logic. Each extra (or removed condiment) is wrapping around the main item and is treated as that item also. Figure a Russian doll.

  • @MaximilianDeister
    @MaximilianDeister Před 9 měsíci +4

    Used to have decorators done but was using Autofac. It was really simple

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

    We usaully do this kind of decoration for caching the results of the actual service. IMHO this is very clean and you dont pollute the original service with stuff like caching, retrying and such.

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

    In my humble opinion, the fact that we have to go through all these hoops and complexity just to get it to work screams KISS to me. Do it the way we did it before all these dependency injection frameworks. Instantiate your objects and pass them to the ctors. Easy. We see the flow. Less lines of code. The principle of KISS.

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

    This is interesting for extending sealed classes for other things i would probably just use inheritance

  • @xybersurfer
    @xybersurfer Před 4 měsíci

    i was hoping for something more general. this is specific to Dependency Injection, where you can count on the interface already existing. i think we need language support for the decorator pattern because it sucks having to link up all the methods etc (this multiplies the work depending on how many there are). for inheritance we already have language support in the form "class A : B" we need something similar but for the decorator pattern and it would be nice to be able to somehow pick and choose which methods etc. we want to use from the existing class. my gut feeling is that there is a deeper underlying problem in the type system. i like your creativity though

  • @JasonAMauss
    @JasonAMauss Před 9 měsíci +1

    A generic retry method that accepts an Action along with a retryCount and retryDelay (think milliseconds Timespan) is much more reusable in all kinds of situations. This feels like an antipattern as far as decorators go.

  • @eramires
    @eramires Před 8 měsíci

    As said in other comments, I prefer to do this kind of extension with Delegates, it's much more decoupled and easier to read and maintain. 🙂 Just need to be careful with memory allocations. 🙂

  • @ericblankenburg
    @ericblankenburg Před 9 měsíci +1

    We've been able to do this in a much cleaner way with Autofac and other DI containers for a long time. Microsoft needs to implement it in their DI container.

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

    9:10 needs to receive more love! :D

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

    Nick you are og, i love it.

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

    How do you feel about using Scrutor for decorating instead?

  • @danielschmid8530
    @danielschmid8530 Před 8 měsíci

    So what if I want to decorate a class with multiple decorations? Right now the decoration receives the implementation via DI in the constructor. What would the second decorator get? Must be the first decoration right? At this point what's the difference to the Chain of Responsibility pattern other than the junctioning to the IServiceProvider?

  • @dev-on-bike
    @dev-on-bike Před 3 měsíci

    So using standard m$ DI u don't get much out of the box for some advanced dependency injection scenarios but if u switch to Autofac things changes drastically as u get some goodies from first day. Personally I wouldn't go with any attributes for DI to not polute classes with some messy attributes, so what is where injected it is a responsibility on registration level in DI container.

  • @alirezanet
    @alirezanet Před 9 měsíci +3

    I keep using scrutor library for decorating things, but for 1 lvl of decoration it is nice feature

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

      We've been using Scrutor as well. Very easy to use.

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

    what if there are more implementations and I want to inject sometimes an implementation, and other times another implementation? should I register every combination? just like a strategy pattern

  • @rpij688
    @rpij688 Před 9 měsíci +1

    I don't like adding the FromKeyedService attribute to the implementation class, because now this class is dependent on a DI container.

  • @Esgarpen
    @Esgarpen Před 8 měsíci

    Please just give us a master video on Dependency Injection already xD I'm talking factories, required services, .. etc. basically a compilation video of "good practice and cool things" you can do with DI in C#

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

    I am looking for this, but then a "genric" variation, e.g. a class that retries all functions of an interface. Not sure how to do this tough, maybe some proxy class/castle core can do this.

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

    Hey Nick, enjoyed your talk and our chat at NDC today, keep it up with the great content!

  • @harkiratsingh4947
    @harkiratsingh4947 Před 3 měsíci

    What about extension methods Nick , they also can modify behavior of a class without touching it ?

  • @michaelsutherland5848
    @michaelsutherland5848 Před 9 měsíci +1

    That's a great use case for goto, I'd never thought of it. I've always used recursion with a counter variable. Nice

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

    9:36 this is edging kinda close to the service locator antipattern / just injecting the implementation.
    It is crucial that the ResilientWeatherService decorator implementation defines and owns its decorator key - i.e., that "og" needs to be defined within the ResilientWeatherService, and unique in the system (I suggest using a const GUID)

    • @Sindrijo
      @Sindrijo Před 9 měsíci +1

      In C# 11 with virtual static members in interfaces you could do it in a way that that is strongly typed, you could also do by key. Example:
      public interface IServiceDecorator where TService : class
      {
      public static abstract TService Decorate(TService serviceToDecorate);
      }
      public static class ServiceExt
      {
      public static void AddDecoratedSingleton(this Services services)
      where TService : class
      where TImplementation : TService
      where TServiceDecorator : TService, IServiceDecorator
      {
      services.AddSingleton();
      services.AddSingleton(locator => TServiceDecorator.Decorate(locator.GetRequiredService()));
      }
      }
      public class ResilientWeatherService : IWeatherService, IServiceDecorator
      {
      public static IWeatherService Decorate(IWeatherService toDecorate) => new ResilientWeatherService(toDecorate);
      private readonly IWeatherService _decoratedService;
      private ResilientWeatherService(IWeatherService realService)
      {
      _decoratedService = realService;
      }
      public Task GetWeatherInCityAsync(string cityName)
      {
      return _decoratedService.GetWeatherInCityAsync(cityName);
      }
      }
      But this still only supports one decorator.

  • @AlFasGD
    @AlFasGD Před 9 měsíci +2

    For the retry logic I much prefer wrapping the trial in a while (true), and breaking the loop by throwing the exception after retrying too many times

  • @T___Brown
    @T___Brown Před 9 měsíci +2

    Or just do an extension on the interface to do the retry logic.
    As a demo sure this is fine to show something but not a fan of the method

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

    I think it is similar with @Inject("key") in Angular

  • @jewersp
    @jewersp Před 8 měsíci

    I'm not sure if using the keyed service really is cleaner as you say. Your decorated service now needs to know about the key. Is that really an improvement?

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

    Don't let the haters tell you that this isn't a valid case for goto :D even nicer when you change it to catch (Exception) when (retryCount

  • @Enhakiel
    @Enhakiel Před měsícem

    I'm a little confused what are the benefits over inheriting the class and overriding a virtual method? plus you have to re:implement again the whole interface....

  • @bvboi
    @bvboi Před měsícem

    When using design patterns, do we really need to follow what it tells? Or just use some parts of it. Because from what I have read, the participants for this pattern are all classes and no Interface.

  • @sanphir
    @sanphir Před 9 měsíci +1

    Oh yes! Decorating pattern holy wars in comments!

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

    The goto made me cry :)

  • @j1shin
    @j1shin Před 8 měsíci

    Decorator also known as Wrapper. Once again a thing that I used in the past without knowing the name.

    • @cdoubleplusgood
      @cdoubleplusgood Před 8 měsíci

      This is not quite correct. "Wrapper" is a more generic term used for different patterns, but most of the time it is used as a synonym for the adapter pattern. And: Decorator and adapter are two different patterns. The decorator exposes the same interface as the inner service, the adapter exposes a different interface.

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

    I think we can use scrutor nuget package to decorate in a simpler way

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

    Another great content ❤❤

  • @surgeon23
    @surgeon23 Před 9 měsíci +2

    Really don't like the key based approach, mainly because of the introduction of a string and the dependency on the attribute.

  • @levmatta
    @levmatta Před 9 měsíci +2

    The key is a problem. How about it being the namof the implementation class?

    • @nickchapsas
      @nickchapsas  Před 9 měsíci +2

      Yeah could totally be that as long as it’s unique

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

      @@nickchapsas C#11's static abstract interface members:
      public interface IServiceDecorator where TService : class
      {
      public static abstract TService Decorate(TService serviceToDecorate);

      public static abstract Guid ServiceKey { get; }
      }
      public class ResilientWeatherService : IWeatherService, IServiceDecorator
      {
      private const string SERVICE_KEY = "F5E3314A-E75E-4D8D-A5E0-3A1840FCF899";
      public static Guid ServiceKey { get; } = new Guid(SERVICE_KEY);

      public static IWeatherService Decorate(IWeatherService toDecorate)
      {
      return new ResilientWeatherService(toDecorate);
      }
      private readonly IWeatherService _decoratedService;
      public ResilientWeatherService([FromKeyedServices(SERVICE_KEY)] IWeatherService realService)
      {
      _decoratedService = realService;
      }
      public Task GetWeatherInCityAsync(string cityName)
      {
      return _decoratedService.GetWeatherInCityAsync(cityName);
      }
      }
      public static class ServiceExt
      {
      public static void AddDecoratedSingleton(this IServiceCollection services)
      where TService : class
      where TImplementation : TService
      where TServiceDecorator : TService, IServiceDecorator
      {
      services.AddSingleton();
      services.AddSingleton(locator => TServiceDecorator.Decorate(locator.GetRequiredService()));
      }

      public static void AddKeyedDecoratedSingleton(this IServiceCollection services)
      where TService : class
      where TImplementation : TService
      where TServiceDecorator : TService, IServiceDecorator
      {
      services.AddKeyedSingleton(TServiceDecorator.ServiceKey);
      services.AddSingleton();
      }
      }

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

    Use a decorator base class and Autofac. Base class adds pass thrus, decorators only have to override methods they care about.

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

    This seems to result in a situation where it would be technically "correct" or "legal" to inject the ResilientWeatherService as the dependency to itself since the only requirement is that it implements IWeatherService, which of course would end up in rather strange behavior. So what ResilientWeatherService actually requires to function properly is a "real" WeatherService, and that's not really evident from the code and neither is what is a "real" WeatherService unless you dig into the implementations. Seems bit more of a clever than a good solution.

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

    it seems you can just auto generate the key instead of having it be set manually. you can have multiple bases this way.

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

      But then you have to reference that key in the class that needs that implementation, and you have to do that in a static way. So you can't auto-generate that key. You might as well not use keys at all then, and create an extension method that wraps the original key-less code, I guess.

  • @JurassicRap
    @JurassicRap Před 2 dny

    Thanks for explaining this to us Nick but it's more complexity for no value...

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

    OG, okay I know exactly what you want to say🤣

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

    Extension everything

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

    What about scoped services? Is it required to configure it as singleton?

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

    Seems familiar 😜

  • @user-lm9jm9ql1t
    @user-lm9jm9ql1t Před 9 měsíci

    is there somebody like Nick Chapsas but teaching python?

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

    Every comp. science students should watch Nick's vides imo. You're not going to learn programming, instead improve your vision. As Cse students the least thing we do is coding at school, we learn a lot of theory etc. And thats the youtube channel where you how to bind theory into code. I'm recommended your videos not only for this kinda videos but low-level understanding videos like the ones with Spans etc. People like Nick, sees a new feature, thinks differently, and be like "What if I use it for this also?" and this kind of vision-improving videos comes. Thank you master :)

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

    Another use of middleware chain pattern and another ache for the true AOP support at language syntax level.

  • @IvanRandomDude
    @IvanRandomDude Před 9 měsíci +3

    Looks like a named beans mess in Java. But at least my method "dOeS nOt Do MuLtIpLe ThInGs" so Uncle Bob can be happy.

  •  Před 9 měsíci +8

    IMHO keyed services increase complexity in a place where most of the stuff is 'hidden' from the developer (DI) so it may be hard to understand what is going on in a larger project. I do not like the KeyedService attribute on the constructor .. but it is probably fine in a project where this is common and developers understand the paradigm. I personally would avoid placing the original (final) service in the DI completely. Even in the first example I would not use x.GetService to get the original (final) service but I would 'new' it within the method where the decorator service is created.

    • @z0nx
      @z0nx Před 9 měsíci +1

      It's like everybody is playing the floor is lava, but where the rule is "avoid new() at all costs". The whole ecosystem is full of these kinds of things. Automapper: avoid writing a mapping function, which I kind of get honestly. Then there is fluentvalidation, which forces you into relying on reflection and interfaces just so you can avoid writing if statements in favor of chaining methods. We just really don't like 'simple' code.

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

      @@z0nxThis made my day!

  • @m_rray
    @m_rray Před 9 měsíci +1

    I don’t think this is good practice. Decorators shouldn’t care about the order, by doing this you’re adding knowledge of the order in which they’re used i.e. the resilient service always wants the “og”? What if you want to add a second third fourth decorator? Improper use of the keyed services imo.
    What if you wanted to change the order I.e. before you had logging > resilient > og and you want to swap logging and resilient over? Then you’re violating the open/closed principle that you originally made the decorators to solve by editing class code, instead of simply changing your composition in the app root.

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

    I don't like this approach. In the end, it doesn't save a registration to the DI container, and ends up coupling the decorator to a specific instance through a magic string. High coupling without type integrity seems to me like the worst of both worlds.
    I find that the FromKeyedServicesAttribute to be an easy trap to fall into if you're just going to use it as-is in your code. That being said, I can see more interesting uses for it with codegen libraries that would produce proxies, such as an AOP framework.

  • @stefanotorelli3688
    @stefanotorelli3688 Před 9 měsíci +2

    goto... welcome to the 70s!

    • @Tsunami14
      @Tsunami14 Před 9 měsíci +2

      I had to check to see if I somehow time-skipped to April Fool's Day.

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

    Why do you use Postman for the simplest cases while you have HTTP Client right in Rider?

  • @pyce.
    @pyce. Před 9 měsíci +1

    I understand that you try to show the concept @nickchapsas and you even note that one should do it their own way, but I just don't agree that this is the right way to demonstrate anything at all. It opens the gate for some inexperienced developers to take away the wrong message and produce unnecessary, convoluted code. 😢

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

    I call bs. Using the key locks you into that key, can't swap out the `OpenWeatherService` against the `WewtherComWewtherService` without modifying the `ResiliantWeatherService`. This impl is basically a 180° rotation back to the start but a bit cleaner.
    The `IWeatherService` is for consumption. The `IRawWeatherService` is for the API call. `IBaseWeatherService` has all the members. Both `IWeatherService` and `IRawWeatherService` inherit from `IBaseWeatherService`.
    The `ResilientWeatherService` implements `IWeatherService` and takes `IEnumerable` via DI.
    The resilient service can now do
    1. Retying
    2. Chain if responsibility
    3. ...
    This is one of the few cases where we throw multiple interfaces into one file.
    Annotate the `IBase*` with some do not use directly warning or mark as obsolete, and suppress in in the other interfaces.

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

    Why do MS make things so obscure. I much prefer AutoFac’s RegisterDecorator approach. The method gives clear meaning and you don’t need to specify a f’ing key.

  • @Spirch
    @Spirch Před 9 měsíci +3

    wow, it went from 21.13c to 27.35c in minutes 😛

  • @SilentTremor
    @SilentTremor Před 9 měsíci +1

    Nope, this is just a service collection trickery

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

    No! This does not allow you to decorate further, it's now locked. Say you wanted an analytics decorator between the decorator and the decoratee? You could not do that without modifying the decoratee. Also, the decoratee should not know it's being decorated.

  • @ryan-heath
    @ryan-heath Před 9 měsíci +1

    +1 for the proper use of goto.
    In this case goto is not evil at all make more sense than a loop.

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

    5:49 this doesn't look weird, this looks exactly like how this should be done

    • @pyce.
      @pyce. Před 9 měsíci

      you can't be serious

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

      @@pyce. I'm not talking about the Goto, I'm talking about the pattern implementation

  • @jessietheandroid
    @jessietheandroid Před 9 měsíci +3

    I can see this getting confusing during a code review, and I would reject this if I saw it come through for anything that wasn't a wrapper for something we didn't have access to. Even then, I'm going to demand that either the DI be set up in a more readable way, or the service naming be clearer that it's a wrapper, and not run the risk of accidentally injecting itself infinitely if the DI setup is slightly wrong. This falls under "clever code" and should be rejected. Clever might not be bad, but if you come back to it 6 months later, are you going to know exactly what's going on at first glance? The video had to explain it, and it still doesn't "add behavior" to existing classes, so much as wraps them. "Adding behavior" is an extension method, not a wrapper.
    I might be arguing semantics here, but spending as much time as I do fighting with code that was written like this over the course of years has given me a serious distaste for clever code that conceals something in some way. And the way the injection is set up here fits the bill perfectly. If you're wrapping a concrete implementation, inject the concrete implementation. Make the consumers of that implementation use the interface. Be explicit about it.

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

    Interesting concept, but far too much of a kludgy hack for my personal taste.

  • @user-tk2jy8xr8b
    @user-tk2jy8xr8b Před 9 měsíci +1

    Would be cool to have services.AddSingleton().DecorateWith().DecorateWith().DecorateWith();

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

    I don't like this approach. It seems to be distributing the knowledge over what needs injected into multiple places because now the decorator service needs to know the attribute and the key to use for the injected service, in addition to having this all still controlled at the service registration point. IMO it's just better to stick to the service registration and using a factory there. It's cleaner and keeps the knowledge of how the service decorator is set up in one place.

  • @user-xn5do6xc1u
    @user-xn5do6xc1u Před 9 měsíci

    You are using labels to jump in the code? why not just put while or do while?

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

    "GoTo"? OMG

  • @kevman2296
    @kevman2296 Před 9 měsíci +1

    Well no, not going to use that

  • @ti83magic
    @ti83magic Před 9 měsíci +2

    Not the biggest fan of this, if I'm honest...

  • @muttBunch
    @muttBunch Před 6 měsíci

    LOL, "og"...'original gan...service'

  • @MatinDevs
    @MatinDevs Před 5 měsíci

    original what?? 😂

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

    Kuch nahi samjha 😢

  • @seg3663
    @seg3663 Před 6 měsíci

    This is just wrong. By using key-based injection attribute in a service You clearly broke inversion of control paradigm in a way that the service now is aware of DI logic and you made it coupled to DI. Smells like an evident anti pattern. The service should not give a shit about injected dependecies creation details and DI mechanics related to that.

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

    very bad code

  • @Paul-uo9sv
    @Paul-uo9sv Před 9 měsíci +7

    If you keep extending and extending isn't that going to have other developers get more confused new Developers