Dependency Injection Is Now Complete In .NET 8!

  Рет қаралды 88,075

Nick Chapsas

Nick Chapsas

10 ай бұрын

Use code ARCH15 and get 15% off the brand new Solution Architecture course on Dometrain: dometrain.com/course/getting-...
Become a Patreon and get source code access: / nickchapsas
Hello, everybody, I'm Nick, and in this video, I will show you a brand new feature that was added in .NET 8 for Dependency Injection that many people, including myself, were missing.
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

Пікірлер: 266
@veljkozrnic3897
@veljkozrnic3897 9 ай бұрын
The use case that's actually useful for this is providing multiple versions of your API. You decorate your services worth attributes that specify versions, you inject specific version based on the requested API version that was invoked.
@Chris-ud8bi
@Chris-ud8bi 9 ай бұрын
Underrated comment
@RandallEike
@RandallEike 9 ай бұрын
Regarding naming the keys for injection, they should be named for their purpose, not for their implementation. Instead of "openweathermap" and "weatherapi" they should be "main" and "backup". That is the point of injecting interfaces as in the future you may decide to prefer weatherapi as you main service for example.
@Psykorr
@Psykorr 9 ай бұрын
Ok not really the piont of the video I guess but maybe it is a correct statement any way I think
@robslaney3729
@robslaney3729 9 ай бұрын
You also now have to know which one you want at compile time. Can't switch to backup without recompiling.
@Rider0fBuffalo
@Rider0fBuffalo 9 ай бұрын
This makes sense to me, because using names of service implementation itself is pointless because you might as well just register, and resolve the service by class instead of by interface.
@gregorymeadows3572
@gregorymeadows3572 9 ай бұрын
@@robslaney3729 He didn't show it here as its implied, but you would conditionally choose which one to use where based on whatever logic your business needs, feature flags or whatever. (If X request fails, call Y instead)
@MikeMcGranahan
@MikeMcGranahan 9 ай бұрын
The author makes this point at the end of the video. Would've been better to demonstrate it in the example code.
@mrwensveen
@mrwensveen 9 ай бұрын
This feels suspiciously like the service locator antipattern. Also, it breaks separation of concerns somewhat, unless your concern is the fallback mechanism specifically. I'd create an IWeatherService implementation, FallbackWeatherService, or something, which would take two (or a list of) IWeatherServices and register that in the DI container.
@robl39
@robl39 9 ай бұрын
100% agree service locator makes me vomit!
@MikeMcGranahan
@MikeMcGranahan 9 ай бұрын
The keys used in the code example do reflect bad practice. But the discussion at the end about "throttled"/"unthrottled", "internal"/"external", "cached"/"uncached" are valid use cases where this feature can be used in a Good™ way.
@dirkp.6181
@dirkp.6181 7 ай бұрын
​@@MikeMcGranahan But still, those are technical concerns and must by no means litter business code.
@ddruganov
@ddruganov 9 ай бұрын
if you hardcode a key when requiring a service through di then what is even the point? why not inject the service directly without an interface?
@PublicVoidFoo
@PublicVoidFoo 9 ай бұрын
The main reason would be so that you could still mock your dependency in unit tests
@ddruganov
@ddruganov 9 ай бұрын
@@PublicVoidFoo okay yeah makes sense thanks
@MrEnvisioner
@MrEnvisioner 9 ай бұрын
Am I missing something as to why a "keyed" service with an alias is preferable to just explicitly registering the service by its own type when you want to request a *specific* instance? If not that, then as others mention, a factory that handles resolving the service for you is the smartest and most reliable solution. I dont really get why someone would even need something like this.
@Stealthy5am
@Stealthy5am 9 ай бұрын
One reason for not registering and resolving by the concrete type is you'll not be able to mock these dependencies in unit tests. Alternatively, you can make a "sub-interface" for each key, but then you end up with marker interfaces, which is not much better. Although, I do think this feature is mostly just bloat and the problem can easily be solved by using factories as you mentioned. In my experience, this problem does not come up often enough to warrant bloat in the library, but MS probably has more data to justify their decision.
@stevenodlum4563
@stevenodlum4563 9 ай бұрын
My assumption would be for unit testing. Decorating the interface with the alias just tells dotnet to use a specific implementation when the API is running normally, but you can still manually provide mocked services for unit tests.
@justgame5508
@justgame5508 9 ай бұрын
Less abstraction I guess, this doesn’t require a factory with some CreateClient() logic and a class to go along with that to resolve a service. It’s just the service you want and a name, which has its benefits (less indirection). Then again I think this syntax in the constructor parameters is ugly so I’d personally chose a factory over this
@vonn9737
@vonn9737 9 ай бұрын
@@Stealthy5am You can register both with their own interfaces which inherit a base interface. IOpenWeatherApi : IWeatherBase and IWeatherApi : IWeatherBase. So that's no problem.
@gileee
@gileee 9 ай бұрын
Cause Java Spring has it...
@RandallEike
@RandallEike 9 ай бұрын
This demonstrates how to get both the main and backup services for retrieving weather. But what I thought you were going to show is how to gracefully degrade to the backup when the main service is down; that is the more interesting problem here.
@RandallEike
@RandallEike 9 ай бұрын
@@jkdmyrs yes, I realize you could simply try and fall back there, but that isn't very elegant. If one service is down (or worse, very slow) your API slows down. And perhaps that business logic is not appropriate to house in the controller either. Polly is designed for dealing with failures, but how to use Polly in this situation is not completely trivial.
@KnightSwordAG
@KnightSwordAG 9 ай бұрын
I would add one use case I see frequently that this solves more elegantly. We use a lot of Dapper here, and so our services regularly need an IDbConnection, but sometimes to two differrent databases (different connection strings). Because a service or repository class needs an IDbConnection, currently, we have to do a lot of extra work at the DI registration to figure out which IDbConnection we need for the service we're calling. With this, we can declare at the service's constructor which IDbConnection we need, or expect. Or at the DI registration, get the keyed service before calling the service's constructor.
@Fred-yq3fs
@Fred-yq3fs 9 ай бұрын
Scary! Your container should not contain any app logic let alone any complex logic. It's not the job of a container, it's typically the job of a factory. Keyed services are simple factories. It's sugar to avoid writing a factory. If you find yourself calculating the key in your callers, then that scattered logic would better live in a factory. If your client passes an enum and it alone decides which implementation to use then fine: use keyed services and write less code.
@Nworthholf
@Nworthholf 9 ай бұрын
In that case connections to different databases should be under their own respective interfaces tho, otherwise you are defying the point of using DI
@KnightSwordAG
@KnightSwordAG 7 ай бұрын
@@Fred-yq3fs you misunderstand. It ultimately becomes a factory of keys to db connections. And it always seemed weird to me to pass the factory as a dependency to a class that only needs the connection.
@petewarner1077
@petewarner1077 9 ай бұрын
Used to use Autofac back in the day, and while I understand adding this for completion, it's not been a feature I've missed. Having to annotate the dependency requires knowing the key at design time, which feels (to me) like it violates the idea of "inversion of control". When I've had a use case to use one of N implementations in the past, I've just registered a good old factory delegate that would hand me the registered service I needed based on the function parameter I passed in. Having said that, it does allow a neater method for creating decorators instead of using something like Scrutor or rolling your own decorator extensions.
@tkrafael
@tkrafael 9 ай бұрын
Using a factory might violate service locator anti pattern. And because method/constructor signature doesn't have explicit dependency fire that service (only to factory) it would be harder to test and troubleshoot missing dependencies
@petewarner1077
@petewarner1077 9 ай бұрын
@tkrafael I don't think it violates that because the delegate merely chooses a service implementation based on inputs, like moving a switch statement out of inline to the container. The client code doesn't take a dependency on IServiceProvider, just a Func.
@kaizer-777
@kaizer-777 9 ай бұрын
Another work-around is to inject a factory class that can resolve your dependency based on whatever key as well. This new approach would be a little cleaner though.
@metaltyphoon
@metaltyphoon 9 ай бұрын
Or if you don’t need to mock, just registered a class without interface.
@sheveksmath702
@sheveksmath702 9 ай бұрын
Just curious, but why would you prefer a factory over this?
@kaizer-777
@kaizer-777 9 ай бұрын
@@sheveksmath702 I wouldn't. I was pointing out another work-around.
@JonWoo
@JonWoo 9 ай бұрын
I would also prefer a factory over this. This approach has the controller deciding which service to use.
@joelhodes1619
@joelhodes1619 9 ай бұрын
@@sheveksmath702if you want the business logic to be dynamic rather than static and outside the remit of the controller. Eg if context user is premium subscriber give him the latest weather from live service otherwise use a cached version.
@a-minus-b-equals-a
@a-minus-b-equals-a 9 ай бұрын
While interesting, I can't think of a use case for this. In a scenario like the one you've described, I feel a better solution would be to create a singleton wrapper class that takes in IEnumerable and cycles to the next service whenever a 500 is returned(or any other "cycle to next" conditions). That would allow setting up a variable amount of backup services without requiring the usage of keys.
@tkrafael
@tkrafael 9 ай бұрын
Suppose you have a multi tenant system that checks for user's phone balance. Whenever your api is called, you have to call balance api on carrier's api. That api does not have a default contract, to the point done aren't even using http/rest. By using keyed service, you are able to resolve a specific implementation from user's carrier.
@a-minus-b-equals-a
@a-minus-b-equals-a 9 ай бұрын
@@tkrafael I might be missing something here. If, from the same API route, we want to get a different service based on the caller's carrier, how would it work with this system, given that the keys are hardcoded? The only way I can see this working is if we use a proxy wrapper class/dictionary to map to the correct service, rather than specifying a hardcoded key for endpoint.
@sebastianxx3687
@sebastianxx3687 9 ай бұрын
how about for example as part of strategy pattern ? 1 payment interfaces - 3 different implementations in 3 different services
@a-minus-b-equals-a
@a-minus-b-equals-a 9 ай бұрын
@@sebastianxx3687 If the different implementations need to have a distinct identity, imho it'd make more sense to add an intermediate interface to distinguish between them. So, if you have multiple IWeatherService that need to be distinguished from each other(maybe by a proxy factory class which then returns them as generic IWeatherService), instead of [FromKeyedService("openapi")], you'd implement an interface that inherits IWeatherService, so you'd request IOpenAPIWeatherService instead. The end result is about the same, so using keys just feels like a weak-typed alternative.
@Nworthholf
@Nworthholf 9 ай бұрын
@@sebastianxx3687 its not a container's concern to choose strategy. Binding it that way denies you the main purpose of using DI, which is implementation agnosticism
@JerryFederspiel
@JerryFederspiel 9 ай бұрын
Thanks for mentioning Scrutor! For needs like caching, retries, etc., I've always manually wired up decorators, and it looks like Scrutor should make that much cleaner.
@jfpinero
@jfpinero 9 ай бұрын
I use scrutor to decorate services that need caching, works really well the [Decorate] attribute.
@mkwpaul
@mkwpaul 9 ай бұрын
I really don't like the idea of having to modify some implementation in order for the dependency injection to work as expected. If I write a service to call some API, read from a db or do literally anything else, it shouldn't concern itself with how it is treated by some other part of the code. It should simply demand its dependencies and expose its functionality. And I don't need a DI container to implemenent any service itself. In this example I think I'd much rather have a third IWeatherService implementation which takes a number of implementations and contains the logic of when to choose which and fowards the interface calls and then just register that one. You could alternatively have a WeatherServiceResolver service that does the resolving and returns the chosen implementation. Although that would have the same issue as the keyed stuff. Anything that needs a weatherService, needs a weatherservice and shouldn't concern itself with the fact that I might wanna dynamically choose between different implementations, or that I use a DI container.
@pavfrang
@pavfrang 9 ай бұрын
A factory is the best of all worlds, in order to create any different type of instances. Thanks for the great presentation!
@Nworthholf
@Nworthholf 9 ай бұрын
I genuinely hoped they will never bring it to default DI. It is quite an antipattern that breaks the whole point of using DI, which is explicitly about _not_ specifying desired implementation. Loose coupling goes straight out of the window with the "keyed DI" approach.
@jelle2819
@jelle2819 9 ай бұрын
Agree, the cases people use this for tend to be fragile and non intuitive. Even Nick falls for that. I have seen layers of cache, dbcached and remote layers as adapters. And then somebody forgets to use the key. They just get one... but wich... all uses of keyed injection result in a huge nightmare. I'd happily write an analyser that flags this feature as a design error 😂
@wojciechwilimowski985
@wojciechwilimowski985 9 ай бұрын
Can you then inject Dictionary and pick your service out in the constructor? The attribute looks clean and all, but it looks like most of the benefit is lost if I have to hardcode the key
@EikeSchwass
@EikeSchwass 9 ай бұрын
I would really love for custom resolve methods. For example Would prefer to have a class A { A(ILogger logger){}} instead of class A { A(ILogger logger){}} and have it resolve depending on what type it targets
@user-nq8ln7ps7x
@user-nq8ln7ps7x 9 ай бұрын
Back in the day Ninject has different approach for that. It was something like Bind().To().WhenInjectingInto(x => *filter*); //or WhenInjectingInto() And that was better, because you still manage your dependencies in startup, and not hardcoding some "alias" in your dependent class. As other comments mention, approach with Keyed/Named services is not any better than just binding different services to different (inherited) interfaces - dependent classes should know that they want, they should known name/key/alias.
@dobripopov8466
@dobripopov8466 9 ай бұрын
Definitely the Ninject approach is better. It is container's responsibility to inject the correct implementation of a specific interface. The "consumer" should NOT be aware of what instances have been registered inside the container and to know their keys/names. Hopefully it's not too late for Microsoft to redesign their DI framework before the release in November.
@AhmedMohammed23
@AhmedMohammed23 9 ай бұрын
sweating from 20 degrees i would like to invite you to my house in Egypt 😅 20 is when i wear my winter clothes
@dimitrishadrin
@dimitrishadrin 9 ай бұрын
I needed this feature always. And now I use factories or implement my version of keyed wrapper. In new implementation I don't like attributes, in my opinion it should be configurable without attributes. And fully agree about decorators and convention.
@dirkp.6181
@dirkp.6181 7 ай бұрын
Caution with usage of keyed/named services, because it might introduce code smells. If the services are meant for redundancy, they are necessarily _semantically_ equivalent. Hence it should be transparent for the consumer and the consuming code should not be forced to chose. To implement redundancy is a separate, technical concern. Create some wrapper with polly for instance, but keep the consuming business code clean! However, if the named services convey different semantics, they should probably be distinguishable not only by some config name, but rather by an interface. Also note, that the naming introduces an dependency, that DI is exactly meant to overcome! "Ask for a fulfilling service and _don't_ care for the implementation!" I confess that I felt like reaching out (in rare occasions) in the past for named services in DI, but meanwhile when running into this it rather makes me think twice.
@bladbimer
@bladbimer 9 ай бұрын
Good honnestly it was the major issue I faced with D.I and as mentionned below I was using factory methods or some functions to provide the good implementation based on key. I reallly hope this will be implemented everywhere (I mean for Worker services, API, Blazor etc.)
@jwcodendaal
@jwcodendaal 9 ай бұрын
Hooray. Been using that for years in autofac. Used a factory recently to acheive that in one project. Nice to have it there now though
@miguelduarte75
@miguelduarte75 9 ай бұрын
Can't think of any use case for this feature but thanks for sharing
@_iPilot
@_iPilot 9 ай бұрын
Does it support injecting multiple implementations as IEnumerable of the same key if several is registered with that key? Or keys must be unique?
@sumitsinghdeo5466
@sumitsinghdeo5466 9 ай бұрын
Its really nice one, I request you to have a session on IAsyncEnumerable implementation and usage. Thanks for sharing the knowledge with us.
@rogeriobarretto
@rogeriobarretto 9 ай бұрын
When you started talking about backup weather services I was thinking the DI would be able to understand what service is healthy as well and return it accordingly. That said, would be interesting if they could expose a interface to help how to resolve which service in case of multiple ones. I believe we would need a intermediary/wrapper Backup IWeatherService that gets both Weathers to property resolve which one to use. That would be an interesting example!
@davidbottiau5408
@davidbottiau5408 9 ай бұрын
I thought the same too. But at the same time I was thinking "How could that even be possible?". If it was possible, it would be magic. However, giving the IEnumerable of registered interfaces, I suppose we can code our own wrapper that will select the best implementation based on your needs. Like exporting a "Ready" instance property. Not sure if DI is abolutely necessary in this context but It's doable.
@paulmdevenney
@paulmdevenney 9 ай бұрын
If they are both singletons then you are actually probably better having an "IsHealthy" ,getting the IEnumerable and chosing the best matching healthy service.
@tkrafael
@tkrafael 9 ай бұрын
For those scenarios, I use scrutor library so I can stack implementation and be able to call as decorated classes
@StephenOwen
@StephenOwen 9 ай бұрын
Today we handle this by having an interface that all of our implementations use, one of which is a public enum value. Then our services that might need one or the other request an IEnumerable from Dependency Injection, and then in their constructor pick the one they need. It will be nice being able to do this natively!
@Kevmoens
@Kevmoens 9 ай бұрын
The one feature I didn’t like was if you need an inline resolution you have to pass the IKeyedServiceProvider through the constructor verse having a way to get a resolving class that is by the interface so you can see in constructor what your dependencies are
@joeldickson5471
@joeldickson5471 9 ай бұрын
You could do this before using a generic in the interface like an enum. I think it's more advantageous if you could use the key inside the ctor so you can use do something like use a database value for the key to dynamical change it.
@sua01n
@sua01n 9 ай бұрын
Great improvement, now I can replace my own written workaround with that :-)
@riccarrasquilla379
@riccarrasquilla379 4 ай бұрын
thanks for the video
@maximer.8190
@maximer.8190 9 ай бұрын
What about creating two interfaces IWeatherApiService and IOpenWeatherMapService, both inheriting IWeatherService? If you have to specify the key where you require the service, it looks the same to me.
@samysammour9983
@samysammour9983 Ай бұрын
Finally! It took a while though but hurray.
@ivandrofly
@ivandrofly 9 ай бұрын
Good one, thanks :)
@jamesmussett
@jamesmussett 9 ай бұрын
I do like the idea, but I personally wouldn't use it. Mainly because it tightly couples your code to the DI framework itself (in this case, Microsoft.Extensions.DependencyInjection.Abstractions). You can achieve pretty much the same thing, albeit not as elegantly, using the factory pattern.
@Nezbo
@Nezbo 7 ай бұрын
Is/will there be a way to get TService[] allOtherImplementations without having to know the keys of other services registered under the same interface? Or Dictionary with the keys.
@snapching
@snapching 9 ай бұрын
I would add that this is a component or plug-in architecture. My preference is to have an attribute on the interface which provides the "key" differentiator. Concrete classes would then define the key rather than the class key provided during registration with the IOC container. Then do ienumerable of the interface in constructor, and in code select the preferred implementation based on business logic.
@MaxParedes
@MaxParedes 9 ай бұрын
excellent video Nick
@matthias916
@matthias916 8 ай бұрын
i always used factories for this, if im understanding this correctly this would be just like having a factory except you dont have to create the instances yourself?
@AndersReinhardtHansen
@AndersReinhardtHansen 9 ай бұрын
Could this be used in conjunction with featureflagging, where you would use versioning or some other functionality to choose which service to use?
@m_rray
@m_rray 9 ай бұрын
Thanks for the video! My only thing is that I wish you’d named the two keys and variables differently. I know it’s not the main focus on the video and it’s just an example in context, but ultimately people will, and do, use these videos as examples. Keying and registering services based on implementation is very leaky. Ultimately you have an interface and any concrete implementation could be used, the consuming code should not know about the implementation. I would generally prefer the use of an enum for example with the values of say “Primary”, “Fallback” etc, and then grab the primaryWeatherService and the fallbackWeatherService. They don’t care about implementation then. In this example, imagine you decided that the weatherApi was now your preferred api, you’d have two choices: one to swap the keys so that they no longer matches tbe implementation which is highly confusing, or go in and edit existing stable tested code to get it to use the weather one first and fallback to open weather - violating the open/closed principle. Using the generic naming all you’d need to do is, in the application root, switch the enum values around so Fallback is now Primary, and then that will be used as the primary, the assignment still makes sense, and we haven’t had to edit lots of code.
@ryancookparagliding
@ryancookparagliding 9 ай бұрын
Not a fan of this feature - I don't like attributes and I reckon the enumerable route with a CanProcess() on the interface is cleaner and also easy to test. Guess there's situations it's useful like heavy service constructors, but I'd argue there's a design problem to consider? Always good to know though - thanks for sharing 🙂
@pranavraj4655
@pranavraj4655 9 ай бұрын
I love this change. 😊
@ukapas
@ukapas 9 ай бұрын
Is there any compile-time protection from mistyping the key?
@TheDimasik9281
@TheDimasik9281 9 ай бұрын
Hi, NativeAOT work for window form?
@Astral100
@Astral100 9 ай бұрын
Wow, finally, I've been waiting for something like that for ages! It always bothered me that you can't use interfaces as they were originally designed to be used to in the Microsoft's dependency injection.
@garcipat
@garcipat 9 ай бұрын
This does not seem to do the same as injecting IEnumerable and filter since you cannot chose on runtime what implementation you want. I often have an Enum wnd different implementation depending on that. Means I need a Func to get the according service during runtime because it may comes our of the configuration or so. Its one Step late.
@Jadenity
@Jadenity 9 ай бұрын
What perfect timing for this. I have a situation that out came up that this fits perfectly. However, I'd like to know what the best way to do this in .NET 6 is (without using AutoFac).
@alexisfibonacci
@alexisfibonacci 9 ай бұрын
I make my services implement a key and then add them to the DI using add multiple. Then when needed GetServices() which returns an IEnumerable which I can then filter with LINQ and pick out the desired one. He went through that around 5:00
@Didymus888
@Didymus888 9 ай бұрын
Just use a factory
@trevorwilson7012
@trevorwilson7012 9 ай бұрын
Personally, I liked the fact that they didn’t implement this feature. If you’re going to bind to something concrete you might as well just bind to the concrete type, rather than use a key to bind an interface that binds to a specific type. This just seems backwards to me. Thanks for sharing though.
@istovall2624
@istovall2624 9 ай бұрын
am i not understanding correctly? i use the service locator pattern that way the specific logic to determine which one is returned can be user/client/customer/use-case/business specific. is the key, different/better? i think it's worse.
@florent9555
@florent9555 8 ай бұрын
Hey, could you not solve your singleton problem with generic interfaces? For example IWeatherService and IWeatherService
@Igahwanoiar
@Igahwanoiar 9 ай бұрын
IDK, I used to intuitively tend to solutions that had keyed registed services, but it never really felt right. The whole point of interfaces is that the dependency is on the service, and the implementation doesn't matter. But if the client needs to pick which registered service is used, doesn't it technically make it a different service? I started using this other methode. It's fair to call it boilerplating, but I wouldn't call it a workaround: just make an empty interface for every named service and have it extend the original interface. No magic strings, no assembly scanners and you get exactly the service that you need, using regular DI.
@temp50
@temp50 9 ай бұрын
I'm not sure if I get it. If we are acquiring the given service by its actual type then why are we trying to register them by the interfaces they implements.
@Fred-yq3fs
@Fred-yq3fs 9 ай бұрын
I used to like the autofac keyed service. But... resolving one implemention is part of the application logic, so it should not be part of the container. In that case, I prefer to use a factory so I'm explicit about resolving. Sometimes the factory is as simple as a key, so granted: factory might be overkill... but more often than not logic creeps in, and that's when factory is the right approach. You really don't want to let app logic creep in the DI setup, especially because it's harder to unit-test. Think refactor cost and risk: if not covered by a unit test you might not dare to refactor, so you're stuck in legacy code, just because you chose to use a fancy feature at some point.
@emerynoel567
@emerynoel567 9 ай бұрын
This does not seem very useful to me, since the key is hardcoded into the injection site. What would be preferable is logic to determine. I have worked on a system with "tenants", where tenants may have their own services. (This was for an insurance company, where each 'tenant' had their own policy system, so we needed to inject services depending on who was calling.) We were able to achieve this with a non-default container, but I don't remember which one it was. EDIT: It was "autofac" I think?
@VeNoM0619
@VeNoM0619 9 ай бұрын
The less 3rd party dependencies the better. Especially if its native C#, since importing 3rd party dlls etc. into cross platform apps can be difficult still (Unity3d). I feel like the native libraries are part of what makes languages take off. Python comes to mind, even though honestly I never fully touched it, but everyone says it can do anything. I also recall some unix libraries having that same adoption rate when they became a jack of all trades.
@Arcadenut1
@Arcadenut1 9 ай бұрын
If you're looking for fail-over then I would expect the IEnumerable would have been a better solution. You try the first item and if it fails you move to the next. Doing the Keyed services you have to know ahead of time all the different services that were registered.
@andrewmcclement4464
@andrewmcclement4464 9 ай бұрын
Perhaps this is better if you want a strict priority between the services, i.e. you care about the ordering.
@egida6486
@egida6486 9 ай бұрын
@nickchapsas Don't you couple your method implementation, to a specific service implementation that way, which defeats the purpose of IoC? Keyed Service seems like a step backwards to me. For such usecases I'd prefer the "inject IWeatherServiceFactory" approach, and put the service selection logic into the factory, instead of relying on a DI-Container feature.
@diadetediotedio6918
@diadetediotedio6918 9 ай бұрын
Nah, this is just untrue. See, the same key can be static and the concrete implementation be different, you can use it as a guide.
@egida6486
@egida6486 9 ай бұрын
@@diadetediotedio6918 if the key is used (reused) it means it is a marker for an abstract concept, which would justify its own interface. if its used to pick out specific implementation from the container, its the service locator pattern and IoC is voilated. Keyed Services still seem like a step backwards.
@Nworthholf
@Nworthholf 9 ай бұрын
@@diadetediotedio6918 if anything, it makes you incapable to mock the selection logic anyway
@mistermeua
@mistermeua 9 ай бұрын
I can not find a good case where i could use this feature for any of my projects now or in the past. I feel itching that we are to spread constant strings around (looks "meh" as for me no matter how you wrap it...) As for me, I'd better inject some factory that relies on some non static (e.g config) props for resolving stuff I need. As other comments suggest. But maybe I just don't yet faced a case when I would need it...
@notoriouslycuriouswombat
@notoriouslycuriouswombat 9 ай бұрын
so the default is always the last registered? kinda wish there was a way to register, and say "this is the default" that way the default is not position dependent
@kenjohnsiosan9707
@kenjohnsiosan9707 9 ай бұрын
thanks and, you didn't show how it would automatically resolve services at runtime when say for example the first service fails.
@TechAndMath
@TechAndMath 9 ай бұрын
In the context of my daily work, we solved this from a business perspective and never need two have multiple service suppliers for the same piece of data. 1. Make sure that our service supplier is not just running the service on one server (can be done via SLA or contract discussion) 2. Make sure that our service supplier has a SLA which guarantee a level of up time and performance time that is acceptable for us As our service suppliers are mainly fairly big boys in their field, we haven't really seen the need to plugin an alternative supplier up to now. Some times their system may go down, but that is within their SLA and our SLA, so it is something can be tolerated. Multiple suppliers always trigger data consistency and its own maintenance issues. So I feel that it is better to be handled by business perspective.
@PereViader
@PereViader 9 ай бұрын
I don't really think saying "we avoided the problem" is the same as coming up with a solution 😅
@TechAndMath
@TechAndMath 9 ай бұрын
Basically the business made the decision or solution and it worked better than a pure dev lead one in this case
@logank.70
@logank.70 9 ай бұрын
I was really hoping it was interceptors. It's really nice being able to add logging to things without having to pepper my code with log statements everywhere. That's the one feature I'm still waiting for.
@ldlework
@ldlework 9 ай бұрын
Use the decorator pattern (I don't mean "decorators")
@logank.70
@logank.70 9 ай бұрын
@@ldlework That does definitely work. It's just nice to be able to define something like logging or performance metrics and be able to attach it to whatever you want without having a bunch of decorators for the different things you want to decorate. Although that could be a naive approach to decorators.
@Ehomer0815
@Ehomer0815 9 ай бұрын
Just bought your new course but it doesnt work :( Only white screen after starting it
@lyrion0815
@lyrion0815 9 ай бұрын
I would register the OpenWeatherMapService without a name, and the fallback one with "fallback". The OpenWeatherMapService would have to be registered last so its made the default by the IoC Container. Depending on the use case I would just resolve an IEnumerable and use the data of the first one that works.
@alexvanheerden5702
@alexvanheerden5702 3 ай бұрын
Strings passed to Attributes must be constants, so how is this different from just injecting the concrete type?
@KJ1987pl
@KJ1987pl 9 ай бұрын
Yeah, for me is great news, generally, I'm always against adding big libraries to projects, especially when they have native support, less dependence is better for all of us (I'm talking about programming only 😅)
@RamonDeKlein
@RamonDeKlein 9 ай бұрын
The question is whether you should use this feature like this. Creating an intermediate provider interface would make much more sense and also makes testing easier.
@robslaney3729
@robslaney3729 9 ай бұрын
IMHO the "key" dependency is the wrong way around. It should be a registration concern, not the resolved. Same issue as base classes having to know about their derived. Worked successful with Unity DI container for years, the resolved instance never had to worry about which implementation it got. Think about conditionally adding a cache wrapper. By using an attribute I have effectively decided at compile time which one I get.. or I change the registration to match what is being requested.. which basically defeats the purpose. Can I use the keyname when I resolve, like with ActivatorUtilities, or registration factory lambda? Will resolving IEnumerable retrieve all the instances, both non-keyed and keyed. If I resolve without the key attribute, will the existing behavior apply that includes key-ed registrations in the last-in best-dressed eval? The biggest issue I have with MS's ServiceCollection is the lack of ability to use a factory with an open generic. You can't get the type(s) being used to resolve. Not common, but very handy when the need arises.
@mitkram99
@mitkram99 9 ай бұрын
Is there a difference in performance between .NET7 and .NET8?
@gamedev_expert
@gamedev_expert 9 ай бұрын
Hi! Don't understand the reason to bind two impl for one interface and then resolve by key. For me it's look like missing L from SOLID.
@diadetediotedio6918
@diadetediotedio6918 9 ай бұрын
You don't need to force everyone to chase your rules when programming bro, just don't use it. But it is not incompatible with SOLID at all, this is good for the O, I and D of SOLID.
@qj0n
@qj0n 9 ай бұрын
Adapters to external systems don't always conform with SOLID, it was meant more for domain level IMO Better example would be to have multiple queue clients connected to different queues - since you use one library, they all have the same interface, but are configured in different way
@gamedev_expert
@gamedev_expert 9 ай бұрын
@@diadetediotedio6918 not forcing, but trying to learn something new
@TonysRacing600
@TonysRacing600 4 ай бұрын
I still don't understand the benefits of those Singleton Services over static variables you can reference.
@SlackwareNVM
@SlackwareNVM 9 ай бұрын
"I wanna know your thoughts on the topic." Me: ... FINALLY!
@Masteroxify
@Masteroxify 9 ай бұрын
Is the any information if Decorator will be present in .Net 8 ?
@finickyflame
@finickyflame 9 ай бұрын
Can you extract those keyed services from the serviceProvider or they are only available using the attribute in the constructor? Personally, I would use that new feature to simplify the registration of mutilple services by their keys, but I would keep the factory pattern to obtain them (The implementation of the factory would use the serviceProvider)
@KnightSwordAG
@KnightSwordAG 9 ай бұрын
At that point you're just wrapping the ServiceProvider. Unless there was a specific abstraction I was attempting to accomplish in the factory (which I kinda doubt, since it's a factory) treating the serviceProvider as the factory is also acceptable. Although I would also point out that this also can reek of the Service Locator anti-pattern, depending on how it's used.
@finickyflame
@finickyflame 9 ай бұрын
@KnightSwordAG Custom factories enforce specific type and arguments to retrieve your specialized service (like the IHttpClientFactory) and might not be related to how you register your service as well. I've made multiple libraries that can be used with or without the DI framework, my apis do not changes with that new feature, but I can now simplify how I register my services when I'm using MS DI framework.
@detach8
@detach8 8 ай бұрын
Isn’t the whole point of DI to remove dependency on specific implementations? By adding keys/removing interfaces we are making the code tightly bound.
@traviscoleman8810
@traviscoleman8810 9 ай бұрын
This feels like a very complicated way to have interfaces, but work around them. Also, this looks like it would make for messy unit testing.
@kabal911
@kabal911 9 ай бұрын
Don’t see how this in anyway affects unit testing, considering that wouldn’t even run though the DI container, and you are still mocking an interface
@joephillips6634
@joephillips6634 9 ай бұрын
it's about time
@lucasterable
@lucasterable 9 ай бұрын
Complete my foot! Wow they still havent implemented: - decorator pattern - interceptors - named instances Amazing how behind .NET DI is in 2023
@samuelschwager
@samuelschwager 9 ай бұрын
Pro: no interface inflation; Con: magic strings. I guess whether or not to use it depends on the use case.
@Nworthholf
@Nworthholf 9 ай бұрын
Its fairly simple - you should never use that thing.If you are going that way you can just as well instantiate everything in place without using DI container at all.
9 ай бұрын
Can you use variables for the key? for example get a value from a configuration at startup and use that value as key to know which service to resolve?
@haxi52
@haxi52 9 ай бұрын
Looks like it has to be a compile time value at the consumer. Because its an attribute.
9 ай бұрын
@@haxi52 I was suspecting that... It removes a lot of potential uses... 😭
@Zashxq
@Zashxq 9 ай бұрын
dometrain course isnt working after purchase 😔
@lyrion0815
@lyrion0815 9 ай бұрын
For me, this features is an absolute minimum requirement for a IoC container (along with a few other features the built-in IoC is still missing), I just added autofac to my projects as soon as I had the requirement for it.
@Nworthholf
@Nworthholf 9 ай бұрын
..but this "feature" is a horrible antipattern that should have never made its way to msdi
@alextelegin6467
@alextelegin6467 9 ай бұрын
Well, 10 years later we might get brand new features like dependency validation and captive dependency check)
@Azcane
@Azcane 9 ай бұрын
Effin FINALY!
@tryagain6148
@tryagain6148 9 ай бұрын
This feature also existed in Unity DI (still Microsoft), and it was way over abused. I prefer to avoid this kind of scenario by adding an identifier to the interface I'm registering that is implemented by the implementation class. In this way, I can do the factory filter in my code... without relying on the DI to do it for me. You know you're screwed when you notice that over 400 instances are name registered in just a simple application.😂
@TheOneAnOnlyGuy
@TheOneAnOnlyGuy 9 ай бұрын
Complete? Did they add decorator support as well?
@niranjanjyothi2416
@niranjanjyothi2416 9 ай бұрын
How about the existing NamedSingelton?
@leonardomoreno23
@leonardomoreno23 9 ай бұрын
Goodbye Scrutor. It was a pleasure ❤
@haxi52
@haxi52 9 ай бұрын
It really feels like the consumer knows too much about the dependency using this feature. As other have pointed out, there are better ways. I would like to see a real work production app that would use this. To me just have two interfaces that implement the 'base' interface and register those. Seems like a cleaner implementation.
@everyonesview
@everyonesview 9 ай бұрын
I have been using Autofac for this until NET 8. Grand! One less external dependency.
@paulalves966
@paulalves966 9 ай бұрын
Castle Windsor DI have that for at least a decade! 😌
@paulalves966
@paulalves966 9 ай бұрын
More 10 years and we may get mixins, property injection, conventional registrations, and MEF 😂🎉
@nikitaklimchuk5032
@nikitaklimchuk5032 9 ай бұрын
I don't like service being dependent on DI container, especially these Attributes, it doesn't allow you to reuse a service using another implementation of interface. Also, it misses "rules" functionality comparing to DryIoc, for my use case - I want to reuse a service using specific key, and I want all nested services to be resolved using that key, doesn't look like it will be possible to do.
@cdarrigo
@cdarrigo 9 ай бұрын
Please do a video on .ConfigureAwait()
@ldlework
@ldlework 9 ай бұрын
Doesn't this violate the open-close principle? The dependent class now needs to statically refer to its dependency (albeit through the key alias). If you wanted to change the behavior of the dependent, you'd have to come in here and modify it. I think in a real scenario, you would not be using the key to identify specific concrete implementations, but rather "flavors" of implementations, like "cached" or "uncached" as you mentioned.
@Nworthholf
@Nworthholf 9 ай бұрын
It absolutely does, and if you are using that you might just as well do back to instantiating everything in place
@nertsch77
@nertsch77 9 ай бұрын
Probably, the title is wrong. It should be called "DI-Container is now complete..." since Dependency Injection does not require a DI Container
@nickchapsas
@nickchapsas 9 ай бұрын
Obviously but titles after a specific length are cropped and DI isn’t picked up by SEO so it had to be that
@allinvanguard
@allinvanguard 9 ай бұрын
About time, this essentially means that other DI providers like Autofac are basically obsolete since they only provided keyed services and some very advanced and exotic use cases like interceptors. But right now, for 99% of my apps, I wouldn't really need these capabilities anymore. Happy to see this in MSDI finally.
@johan.mp4
@johan.mp4 9 ай бұрын
Intereptor/decorator can be achieved in the standard container with just a few lines of code. You don't need a separate library for that.
@allinvanguard
@allinvanguard 9 ай бұрын
@@johan.mp4 Oh, my bad, I meant "Missing binding interceptors", not plain interceptors / decorators. That works pretty well already.
@catq_q6233
@catq_q6233 9 ай бұрын
It's a step in the right direction, for sure, but for Autofac to really become obsolete MSDI still needs to add a lot imo, starting with property injection...
@Rein______
@Rein______ 9 ай бұрын
​@@catq_q6233please no property injection 😢. Does not work right with nullable
@celluj34
@celluj34 9 ай бұрын
@@catq_q6233 You cannot convince me that property injection is not a code smell.
@daddy2claire
@daddy2claire 9 ай бұрын
Resolving a service by name.... isn't that Service Locator - usually considered an anti-pattern?
@Crozz22
@Crozz22 9 ай бұрын
async is a pretty big thing missing
@yurymatsiulka5786
@yurymatsiulka5786 9 ай бұрын
I prefer to work with keyed services when an entity or contract has a discriminator
@bradenb
@bradenb 9 ай бұрын
I don't get the usefulness. I want my interfaces to hide my implementation, so why add an attribute (also yuck) to then request a specific implementation? I'd much rather just inject the concrete type, or even better, just have a more specific interface. Another commenter mentioned that this could be for purpose rather than implementation; fine, but is this really the way to solve that problem? You could have a service dedicated to providing instances dynamically based on purpose rather than tie purpose to a compile-time decision. What's the use case for this?
Making Your APIs Blazingly Fast in .NET 8!
11:45
Nick Chapsas
Рет қаралды 65 М.
Background Tasks Are Finally Fixed in .NET 8
10:29
Nick Chapsas
Рет қаралды 98 М.
Они убрались очень быстро!
00:40
Аришнев
Рет қаралды 1,3 МЛН
Кәріс өшін алды...| Synyptas 3 | 10 серия
24:51
kak budto
Рет қаралды 1,1 МЛН
Шокирующая Речь Выпускника 😳📽️@CarrolltonTexas
00:43
Глеб Рандалайнен
Рет қаралды 11 МЛН
Do you have a friend like this? 🤣#shorts
00:12
dednahype
Рет қаралды 58 МЛН
Dependency Injection, The Best Pattern
13:16
CodeAesthetic
Рет қаралды 739 М.
The New .NET 9 HybridCache That You Must Upgrade To!
14:34
Nick Chapsas
Рет қаралды 41 М.
Why Startups Hate .NET and C#
10:38
Nick Chapsas
Рет қаралды 242 М.
The .NET dependency injection methods you are not using
11:49
Nick Chapsas
Рет қаралды 91 М.
.NET 8 🔥🚀 : Exploring Dependency Injection Features
16:55
Mohamad Lawand
Рет қаралды 2,8 М.
Why Developers Hate "Clean Code"?
14:39
Nick Chapsas
Рет қаралды 43 М.
"Stop Using Async Await in .NET to Save Threads" | Code Cop #018
14:05
Они убрались очень быстро!
00:40
Аришнев
Рет қаралды 1,3 МЛН