Dependency Injection Is Now Complete In .NET 8!

  Рет қаралды 95,686

Nick Chapsas

Nick Chapsas

Күн бұрын

Пікірлер: 268
@veljkozrnic3897
@veljkozrnic3897 Жыл бұрын
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 Жыл бұрын
Underrated comment
@mariusg8824
@mariusg8824 Ай бұрын
Now, that's actually a very valid argument.
@RandallEike
@RandallEike Жыл бұрын
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 Жыл бұрын
Ok not really the piont of the video I guess but maybe it is a correct statement any way I think
@robslaney3729
@robslaney3729 Жыл бұрын
You also now have to know which one you want at compile time. Can't switch to backup without recompiling.
@Rider0fBuffalo
@Rider0fBuffalo Жыл бұрын
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 Жыл бұрын
@@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 Жыл бұрын
The author makes this point at the end of the video. Would've been better to demonstrate it in the example code.
@mrwensveen
@mrwensveen Жыл бұрын
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 Жыл бұрын
100% agree service locator makes me vomit!
@MikeMcGranahan
@MikeMcGranahan Жыл бұрын
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 Жыл бұрын
​@@MikeMcGranahan But still, those are technical concerns and must by no means litter business code.
@RandallEike
@RandallEike Жыл бұрын
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 Жыл бұрын
@@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.
@ChrisWard74
@ChrisWard74 4 ай бұрын
I was hopeing for a demonstration of this too. If the first one is down or rate limited how do we get it to use the second gracefully.
@KnightSwordAG
@KnightSwordAG Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@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.
@ddruganov
@ddruganov Жыл бұрын
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 Жыл бұрын
The main reason would be so that you could still mock your dependency in unit tests
@ddruganov
@ddruganov Жыл бұрын
@@PublicVoidFoo okay yeah makes sense thanks
@petewarner1077
@petewarner1077 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@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 Жыл бұрын
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.
@briumphbimbles
@briumphbimbles Жыл бұрын
I would still prefer a factory over this.
@metaltyphoon
@metaltyphoon Жыл бұрын
Or if you don’t need to mock, just registered a class without interface.
@sheveksmath702
@sheveksmath702 Жыл бұрын
Just curious, but why would you prefer a factory over this?
@kaizer-777
@kaizer-777 Жыл бұрын
@@sheveksmath702 I wouldn't. I was pointing out another work-around.
@JonWoo
@JonWoo Жыл бұрын
I would also prefer a factory over this. This approach has the controller deciding which service to use.
@a-minus-b-equals-a
@a-minus-b-equals-a Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@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 Жыл бұрын
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 Жыл бұрын
@@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 Жыл бұрын
@@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
@ryancookparagliding
@ryancookparagliding Жыл бұрын
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 🙂
@JerryFederspiel
@JerryFederspiel Жыл бұрын
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 Жыл бұрын
I use scrutor to decorate services that need caching, works really well the [Decorate] attribute.
@MrEnvisioner
@MrEnvisioner Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@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 Жыл бұрын
Cause Java Spring has it...
@user-nq8ln7ps7x
@user-nq8ln7ps7x Жыл бұрын
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 Жыл бұрын
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.
@pavfrang
@pavfrang Жыл бұрын
A factory is the best of all worlds, in order to create any different type of instances. Thanks for the great presentation!
@Nworthholf
@Nworthholf Жыл бұрын
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 Жыл бұрын
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 😂
@EikeSchwass
@EikeSchwass Жыл бұрын
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
@StephenOwen
@StephenOwen Жыл бұрын
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!
@AhmedMohammed23
@AhmedMohammed23 Жыл бұрын
sweating from 20 degrees i would like to invite you to my house in Egypt 😅 20 is when i wear my winter clothes
@mkwpaul
@mkwpaul Жыл бұрын
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.
@jwcodendaal
@jwcodendaal Жыл бұрын
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
@rogeriobarretto
@rogeriobarretto Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
For those scenarios, I use scrutor library so I can stack implementation and be able to call as decorated classes
@dimitrishadrin
@dimitrishadrin Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
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.)
@wojciechwilimowski985
@wojciechwilimowski985 Жыл бұрын
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
@m_rray
@m_rray Жыл бұрын
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.
@nertsch77
@nertsch77 Жыл бұрын
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 Жыл бұрын
Obviously but titles after a specific length are cropped and DI isn’t picked up by SEO so it had to be that
@trevorwilson7012
@trevorwilson7012 Жыл бұрын
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.
@miguelduarte75
@miguelduarte75 Жыл бұрын
Can't think of any use case for this feature but thanks for sharing
@logank.70
@logank.70 Жыл бұрын
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 Жыл бұрын
Use the decorator pattern (I don't mean "decorators")
@logank.70
@logank.70 Жыл бұрын
@@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.
@jamesmussett
@jamesmussett Жыл бұрын
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.
@Arcadenut1
@Arcadenut1 Жыл бұрын
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 Жыл бұрын
Perhaps this is better if you want a strict priority between the services, i.e. you care about the ordering.
@lucasterable
@lucasterable Жыл бұрын
Complete my foot! Wow they still havent implemented: - decorator pattern - interceptors - named instances Amazing how behind .NET DI is in 2023
@sumitsinghdeo5466
@sumitsinghdeo5466 Жыл бұрын
Its really nice one, I request you to have a session on IAsyncEnumerable implementation and usage. Thanks for sharing the knowledge with us.
@snapching
@snapching Жыл бұрын
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.
@TechAndMath
@TechAndMath Жыл бұрын
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 Жыл бұрын
I don't really think saying "we avoided the problem" is the same as coming up with a solution 😅
@TechAndMath
@TechAndMath Жыл бұрын
Basically the business made the decision or solution and it worked better than a pure dev lead one in this case
@sua01n
@sua01n Жыл бұрын
Great improvement, now I can replace my own written workaround with that :-)
@Jadenity
@Jadenity Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
Just use a factory
@VeNoM0619
@VeNoM0619 Жыл бұрын
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.
@Astral100
@Astral100 Жыл бұрын
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.
@samuelschwager
@samuelschwager Жыл бұрын
Pro: no interface inflation; Con: magic strings. I guess whether or not to use it depends on the use case.
@Nworthholf
@Nworthholf Жыл бұрын
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.
@KJ1987pl
@KJ1987pl Жыл бұрын
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 Жыл бұрын
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.
@_iPilot
@_iPilot Жыл бұрын
Does it support injecting multiple implementations as IEnumerable of the same key if several is registered with that key? Or keys must be unique?
@samysammour9983
@samysammour9983 7 ай бұрын
Finally! It took a while though but hurray.
@maximer.8190
@maximer.8190 Жыл бұрын
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.
@SlackwareNVM
@SlackwareNVM Жыл бұрын
"I wanna know your thoughts on the topic." Me: ... FINALLY!
@Fred-yq3fs
@Fred-yq3fs Жыл бұрын
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.
@haxi52
@haxi52 Жыл бұрын
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.
@lyrion0815
@lyrion0815 Жыл бұрын
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.
@traviscoleman8810
@traviscoleman8810 Жыл бұрын
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 Жыл бұрын
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
@Igahwanoiar
@Igahwanoiar Жыл бұрын
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.
@egida6486
@egida6486 Жыл бұрын
@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 Жыл бұрын
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 Жыл бұрын
@@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 Жыл бұрын
@@diadetediotedio6918 if anything, it makes you incapable to mock the selection logic anyway
@lyrion0815
@lyrion0815 Жыл бұрын
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 Жыл бұрын
..but this "feature" is a horrible antipattern that should have never made its way to msdi
@mistermeua
@mistermeua Жыл бұрын
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...
@leonardomoreno23
@leonardomoreno23 Жыл бұрын
Goodbye Scrutor. It was a pleasure ❤
@Kevmoens
@Kevmoens Жыл бұрын
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
@TheDimasik9281
@TheDimasik9281 Жыл бұрын
Hi, NativeAOT work for window form?
@gamedev_expert
@gamedev_expert Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@diadetediotedio6918 not forcing, but trying to learn something new
@matthias916
@matthias916 Жыл бұрын
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?
@emerynoel567
@emerynoel567 Жыл бұрын
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?
@eclecticx
@eclecticx 7 ай бұрын
You have good and informative videos, but you should seriously consider a slower cadence. As for this example in particular, it seems to break SoC (antipattern), has some naming issues (implementation rather than purpose), and depends on hard-coding.
@alextelegin6467
@alextelegin6467 Жыл бұрын
Well, 10 years later we might get brand new features like dependency validation and captive dependency check)
@TonysRacing600
@TonysRacing600 9 ай бұрын
I still don't understand the benefits of those Singleton Services over static variables you can reference.
@detach8
@detach8 Жыл бұрын
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.
@tryagain6148
@tryagain6148 Жыл бұрын
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.😂
@colindawson4818
@colindawson4818 Жыл бұрын
I'm going to stick with AutoFac. I've used it for many years, without issues, and don't see any compelling reason to change. The ultimate king for me is performance, and not just at a theoretical level. I'd need to see a practical implementation where it actually makes a big difference in a real world scenario.
@MikeZadik
@MikeZadik Жыл бұрын
stronginject might be a good thing for performance. I understand he/they do the injection at compile time. If you take a look let me know, I have this in my bookmarks for months 😄
@ВладиславДараган-ш3ф
@ВладиславДараган-ш3ф Жыл бұрын
I've seen benchmarks thay show that built-in DI is faster than Autofac
@ricmrodrigues
@ricmrodrigues Жыл бұрын
Main problem with that, which I want to as well, is they've made the built-in in such a way you can't take it out. A bit of a conforming container and a leaky abstraction.
@paulalves966
@paulalves966 Жыл бұрын
Castle Windsor DI have that for at least a decade! 😌
@paulalves966
@paulalves966 Жыл бұрын
More 10 years and we may get mixins, property injection, conventional registrations, and MEF 😂🎉
@garcipat
@garcipat Жыл бұрын
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.
@Nezbo
@Nezbo Жыл бұрын
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.
@florent9555
@florent9555 Жыл бұрын
Hey, could you not solve your singleton problem with generic interfaces? For example IWeatherService and IWeatherService
@AndersReinhardtHansen
@AndersReinhardtHansen Жыл бұрын
Could this be used in conjunction with featureflagging, where you would use versioning or some other functionality to choose which service to use?
@everyonesview
@everyonesview Жыл бұрын
I have been using Autofac for this until NET 8. Grand! One less external dependency.
@allinvanguard
@allinvanguard Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@johan.mp4 Oh, my bad, I meant "Missing binding interceptors", not plain interceptors / decorators. That works pretty well already.
@catq_q6233
@catq_q6233 Жыл бұрын
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______ Жыл бұрын
​@@catq_q6233please no property injection 😢. Does not work right with nullable
@celluj34
@celluj34 Жыл бұрын
@@catq_q6233 You cannot convince me that property injection is not a code smell.
@notoriouslycuriouswombat
@notoriouslycuriouswombat Жыл бұрын
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
@ukapas
@ukapas Жыл бұрын
Is there any compile-time protection from mistyping the key?
@finickyflame
@finickyflame Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@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.
@robslaney3729
@robslaney3729 Жыл бұрын
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.
@yurymatsiulka5786
@yurymatsiulka5786 Жыл бұрын
I prefer to work with keyed services when an entity or contract has a discriminator
@ldlework
@ldlework Жыл бұрын
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 Жыл бұрын
It absolutely does, and if you are using that you might just as well do back to instantiating everything in place
@pranavraj4655
@pranavraj4655 Жыл бұрын
I love this change. 😊
@MaxParedes
@MaxParedes Жыл бұрын
excellent video Nick
Жыл бұрын
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 Жыл бұрын
Looks like it has to be a compile time value at the consumer. Because its an attribute.
Жыл бұрын
@@haxi52 I was suspecting that... It removes a lot of potential uses... 😭
@nooftube2541
@nooftube2541 Жыл бұрын
Top feature. Sad that our architects not good with di and force app developers to use statics or other self written approaches.
@ryancookparagliding
@ryancookparagliding Жыл бұрын
haha that's wild 😅
@Crossbow123
@Crossbow123 Жыл бұрын
Its still missing property injection. Now that we have required properties, this feature is begging to be here.
@kenjohnsiosan9707
@kenjohnsiosan9707 Жыл бұрын
thanks and, you didn't show how it would automatically resolve services at runtime when say for example the first service fails.
@temp50
@temp50 Жыл бұрын
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.
@Zashxq
@Zashxq Жыл бұрын
dometrain course isnt working after purchase 😔
@riccarrasquilla379
@riccarrasquilla379 9 ай бұрын
thanks for the video
@ivandrofly
@ivandrofly Жыл бұрын
Good one, thanks :)
@alexvanheerden5702
@alexvanheerden5702 9 ай бұрын
Strings passed to Attributes must be constants, so how is this different from just injecting the concrete type?
@istovall2624
@istovall2624 Жыл бұрын
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.
@joephillips6634
@joephillips6634 Жыл бұрын
it's about time
@nikitaklimchuk5032
@nikitaklimchuk5032 Жыл бұрын
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.
@TheOneAnOnlyGuy
@TheOneAnOnlyGuy Жыл бұрын
Complete? Did they add decorator support as well?
@Masteroxify
@Masteroxify Жыл бұрын
Is the any information if Decorator will be present in .Net 8 ?
@Crozz22
@Crozz22 Жыл бұрын
async is a pretty big thing missing
@DannyEck
@DannyEck Жыл бұрын
My (brain) at 2:38: "the real f__cking API" (that couldn't be right, rewind 10s) "the real bucking API" (Is that UK slang?, rewind 10s) "the real backing API" (Oh. I'm an idiot)
@mitkram99
@mitkram99 Жыл бұрын
Is there a difference in performance between .NET7 and .NET8?
@Bliss467
@Bliss467 Жыл бұрын
I just want them to remove all the boilerplate from .NET’s DI implementation. Give us the ability to define the dependency at the dependent location at the property level without needing to pass through constructor, like spring does. Also removing the need to give an interface for every dependency, which is more a problem with mocking than with the DI system.
@z0nx
@z0nx Жыл бұрын
You consider constructors boilerplate?
@niranjanjyothi2416
@niranjanjyothi2416 Жыл бұрын
How about the existing NamedSingelton?
Making Your APIs Blazingly Fast in .NET 8!
11:45
Nick Chapsas
Рет қаралды 70 М.
The Logging Everyone Should Be Using in .NET
15:34
Nick Chapsas
Рет қаралды 83 М.
Amazing remote control#devil  #lilith #funny #shorts
00:30
Devil Lilith
Рет қаралды 16 МЛН
AutoEnum: Automate Service Enumeration Like a Pro!
10:36
Dependency Injection, The Best Pattern
13:16
CodeAesthetic
Рет қаралды 882 М.
Why I'm Worried About Blazor and its Future
19:31
Nick Chapsas
Рет қаралды 31 М.
Stop Using AutoMapper in .NET
9:50
Nick Chapsas
Рет қаралды 58 М.
.NET 8 🔥🚀 : Exploring Dependency Injection Features
16:55
Mohamad Lawand
Рет қаралды 4 М.
Dependency injection fundamentals in C# - DI vs IoC vs DIP
13:30
Amichai Mantinband
Рет қаралды 40 М.
What's New in .NET 9 with Examples
25:02
Nick Chapsas
Рет қаралды 40 М.
Dependency Injection in .NET Core (.NET 6)
1:00:32
IAmTimCorey
Рет қаралды 194 М.
.NET and C# are in trouble. Here is what I'd do.
10:57
Ed Andersen
Рет қаралды 101 М.