Structuring Dependency Injection In ASP.NET Core The Right Way

Structuring Dependency Injection In ASP.NET Core The Right Way

Milan Jovanović

1 год назад

49,086 Просмотров

Ссылки и html тэги не поддерживаются


Комментарии:

Jacob Stamm
Jacob Stamm - 28.09.2023 21:12

With the IServiceInstaller approach, how do you handle cases where different web apps need different services? As-is, your approach would install everything everywhere.

Ответить
Alex Mitrakis
Alex Mitrakis - 25.09.2023 07:34

I've been doing the second options for a while now naming it IDependencyInjectionModule. I really like it because they don't need to live in the same project and I can sub in modules fast especially for tests.

Ответить
fifty-plus
fifty-plus - 21.09.2023 16:30

Rosyln Code Generator libraries are best for this. Much cleaner than writing abstractions, with no reflection or massive setup files. Add an attribute and it code generates all the service registrations. Some third party registrations still need to exist but your own code becomes a one line registration per assembly. Clean, explicit and fast.

Ответить
IM Vlogs
IM Vlogs - 19.09.2023 19:21

Very nice approach, your all videos are awesome and unique.

Ответить
Javier Francia
Javier Francia - 06.08.2023 05:15

hi milan! thank you very much for your videos <3

i have a question, why do you choose to return the IServiceCollection in the extension method? is this the same than returning void?

Ответить
Andrey Metkiy
Andrey Metkiy - 19.07.2023 15:17

Why don't you make the method return void when creating methods? It should work

Ответить
tech pc
tech pc - 07.04.2023 12:44

Ответить
Kevin Marchand
Kevin Marchand - 05.04.2023 12:28

Awesome

Ответить
Lazy Koder
Lazy Koder - 23.03.2023 10:01

Service.Install seems very clean, as we can use this at each project (class lib) level so services defined in diff project assembly can we added there only, which would be more clean and explicit.

Ответить
David Cuccia
David Cuccia - 21.03.2023 05:02

Nice summary. And a good reminder that I don't need Scrutor for simple tasks like this. One thought - with C#'s static virtual members in interfaces, we can avoid that extra step to instantiate IServiceInstaller objects, just to call a method (which can now be static).

Ответить
Anton Martynyuk
Anton Martynyuk - 07.03.2023 15:05

Great approach with ServiceInstaller but it also has drawbacks because of reflection. It might be hard to trim your application correctly when using reflection and some apps do require to be self-contained and trimmed. Personally I use extensions methods but write them in different files. The future of DI will be with source generators, so the compiler can check that ServiceA has dependencies on ServiceB and ServiceC and if they are registered in DI. I hope this will be the future of DI which will solve many problems during compile time and it will be way faster than reflection. A quick startup of the app is often critical for such apps as Azure Functions and AWS lambdas

Ответить
RH
RH - 25.02.2023 09:48

Hi Milan, great video. You may use SHIFT ALT and . (dot) to select next occurrence, so you don't have to manually select and paste.

Ответить
Rajesh Aravapalli
Rajesh Aravapalli - 12.02.2023 17:38

No no to reflection. First approach with multiple extension files - may be span across different projects is what i am doing.

Ответить
Adrian Sluijters
Adrian Sluijters - 05.02.2023 05:15

YOu actually touched on some good points here, especially when it came to the service installers side of things... Super video! thanks.

Ответить
bioman
bioman - 01.02.2023 08:49

I used to be a fan of reflection mechanics liked this until I had to reverse engineer my own code several months later so now I think the explicit nature of the extension approach is going to cause you much less headaches in future.

Ответить
Anthony Bianue
Anthony Bianue - 21.01.2023 22:02

Lovely video. My only concerns are Jr dev learning curve and functional testing. The reflection part would complicate the test. But I like it. I am a fan of putting the dependencies at the project level itself. So the infrastructure layer would have one etc

Ответить
Andrey Biryulin
Andrey Biryulin - 10.01.2023 06:52

Biggest concern I have about DI is how to express in code that one bunch of dependencies require some other shared ones, e.g. you have
.AddFeatureX()
.AddFeatureY()
and they both use say IDistributedCache and you want to make sure you didn't forget .AddDistributedCache in your app, but don't want to bind it in either FeatureX or FeatureY, because it might be up to application to bind it to specific implementation and in specific scope maybe.
Neither of proposed solutions help with that.

Ответить
ProtectedClassTest
ProtectedClassTest - 07.01.2023 19:53

We've implemented the first approach on project and now I think neither the 1st or 2nd approach is good. Its just adding another layer of complexity for very simple di statements. What I would do now is just create a single extension method and put all the di code there just so to cleanup the main file

Ответить
Shawn Lewis
Shawn Lewis - 06.01.2023 07:31

Why not use public partial class and refactor them as individual functions? That way the class inside of Program.cs is spread amonst 50 or so files?

Ответить
Cliff Chambers
Cliff Chambers - 06.01.2023 00:14

I've chosen the extension methods approach thusfar. My biggest issue is the solution has about 30 microservice projects and I don't want to recreate all this every time we add a new project, so I'm shoving as much as possible into a class library, which seems to increase complexity a bit.

Ответить
Kristoffer Lindström
Kristoffer Lindström - 01.01.2023 19:57

I like the reflection one more, but it would introduce a longer startup time, something to think about if cold starts in your projects is important for you. In lambdas for example, reflection approach might not be for you.

Ответить
Mahi Uddin
Mahi Uddin - 01.01.2023 10:31

Thanks @Milan, it was a great resourceful video.

Ответить
Drury Yudis Lumenta
Drury Yudis Lumenta - 01.01.2023 05:39

Nice! I'll apply your approach. Thanks.

Ответить
S Afzal
S Afzal - 31.12.2022 09:58

Great lesson. Thank you for sharing these gems for free.

Ответить
Cesar Espitia
Cesar Espitia - 30.12.2022 18:24

Nice and useful. Thank you.

Ответить
Daniele PICCHI
Daniele PICCHI - 30.12.2022 09:54

Great

Ответить
Christoph Wolf
Christoph Wolf - 30.12.2022 04:45

fuck yeah

Ответить
CarmenSantiNova
CarmenSantiNova - 29.12.2022 03:19

We've been using a custom built plugin system for many years now and we use (sort of) the approach of your IServiceInstaller.
It's all good when it comes to service registration but when it comes to handling middleware it needs coordination (since the middleware is sensitive to ordering). And since all of our plugins essentially know nothing about the other plugins, they cannot coordinate amongst themselves.
So we added some meta-information that forms a dependency graph but it didn't solve the problem really.

This is where I realized that there is no good solution to the problem of coordinating middleware order. Basically we're stuck with a hard-coded setup.
Anyone else been playing around with that kind of setup!?

Ответить
Mehul Bhuva
Mehul Bhuva - 29.12.2022 02:28

Do you have GitHub code repo with the code sample shown in the video?

Ответить
Kostiantyn Shyshkovskyi
Kostiantyn Shyshkovskyi - 29.12.2022 00:37

About the second one, I reckon we can run it easier.
We have one interface and a lot of implementations, and in this case, we can have something like this IEnumarable<IServiceInstaller> and then have foreach to call all of them one by one 🙂 Of course, first of all, we have to register all the implementation)

Ответить
Nothing IsReal
Nothing IsReal - 28.12.2022 22:08

The reflection approach is a bad idea. Reflection is rule based. Rules must be resolved by other programmers / yourself. It comes in handy when initially creating the project but later when someone else has to maintain it, this person has to resolve that rule base approach, which can be an obstacle. If you write down in a reasonable way - do it. Grouping the service registrations can be an effective way to improve readability and testability (e.g. you can step over a function if you know it works). On the other hand, you need to navigate to more code files. But both approaches don't make the code more robust. So that is something I would consider doing when nothing else is left to do.

Ответить
Vikas Joshi
Vikas Joshi - 28.12.2022 19:48

Thanks for introducing super compact and maintainable way of doing better DI @Milan

Ответить
Swzvtlbngfd
Swzvtlbngfd - 28.12.2022 17:36

Very helpful in understanding how to organize ever growing dependencies

Ответить
Abdelmonaïm ERRAHMANI
Abdelmonaïm ERRAHMANI - 28.12.2022 12:19

Thanks for the video
when you use Extension methode , you can avoid returning IServiceCollection no need

Ответить
Emily Wagner
Emily Wagner - 28.12.2022 06:12

You're a programming genius, Milan!

Ответить
Pelea Cezar
Pelea Cezar - 28.12.2022 02:00

The second approach is very elegant and at the same time a less common way to inject your dependencies into the project. Congratulations for another extremely useful material 😃

Ответить
Nage
Nage - 28.12.2022 01:05

Love aproach with reflection, doing like that for a some time already )

Ответить
Marcus Kaseder
Marcus Kaseder - 28.12.2022 00:52

Always nice to see different approaches. I even have an analyzer rule that doesn't allow a big program.cs

I usually go with Startup classes (same like your installer). Sometimes with interfaces and sometimes with static methods (no extensions).

But the main difference to your solution is my encapsulation. Sometimes it's not enough to just register services and you have to do some app stuff.

So, my Startup classes mostly have ConfigureServices(ServiceCollection) and also ConfigureApp(App).

In that case AuthAndAuthStartup would have services.AddAuthentication() and app.UseAuthentication()

Same with CorsStartup, SwaggerStartup, etc.

Ответить
Calin Marian
Calin Marian - 28.12.2022 00:40

Second method seems cool, but it can be cases when order if instantiation must be preserved

Ответить
Shakib
Shakib - 27.12.2022 22:34

I think a nice way to reduce dependency registrations, is using Interface marking, but not with tools like scrutor. because it will make application start up slow and heavy (because of reflection stuff). Instead we can create a source generator to wisely check the interface marks and inject them using a partial method.

Ответить
Oleksii Korniienko
Oleksii Korniienko - 27.12.2022 19:29

Thanks for the video! 2nd approach is interesting.
I'd like to mention it. Would it be great to make each layer to be responsible for its dependencies? By doing this we can apply an internal modifier where it is possible and the layer becomes more encapsulated with its own dependencies. Otherwise, we need to keep all implementations public just to register them.

Ответить
Sanam
Sanam - 27.12.2022 18:36

I use the 2nd approach!

Ответить
Mohammad Zare
Mohammad Zare - 27.12.2022 17:07

Great approach. I think it's good to add an order property to specify which dependency should be injected first...

Ответить
Tony Caesar
Tony Caesar - 27.12.2022 16:47

I'm torn between the two options. I have tend toward the first extension strategy in the past. I like the idea of having a different file for each startup type regardless of the strategy. It keeps the code better organized and easier to find startup elements. The reflection approach has a certain sense of magic while still being clean and easy to maintain. Magic for me is bad because it detaches you from what is happening and can be harder to maintain. One catch to the reflection startegy is I may want to selectively switch between different startup extensions to cover different scenarios (mock, test environment, etc.). The reflection strategy makes that a little more difficult but not impossible. Which do you find yourself using more and why?

Ответить
C#_Dev
C#_Dev - 27.12.2022 16:45

Great Tutorial, Can you make a tutorial about unit testing and Mocking testing specifically

Ответить
Mariano Montano
Mariano Montano - 27.12.2022 16:21

I've been using the extension method approach for some time now. It's very clean. The Automatic installer is a very interesting approach too. I saw something very similar a while back, just before .NET Core dependency injection system, in a great instructor's channel from whom I learned a lot (Tim Corey) with Autofac Nuget Package.

Ответить