How Assembly Scanning keeps your .NET code clean

แชร์
ฝัง
  • เผยแพร่เมื่อ 20 ก.ค. 2024
  • Subscribe: bit.ly/ChapsasSub
    Check out my courses: dometrain.com
    Become a Patreon and get source code access: / nickchapsas
    Hello everybody I'm Nick and in this video I am going to talk about Assembly Scanning in C# & .NET and show you how it helps keep your code clean.
    Timestamps
    Intro - 0:00
    What is Assembly Scanning? - 0:42
    Implementing Assembly Scanning - 8:06
    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

ความคิดเห็น • 48

  • @trawsonn
    @trawsonn 2 ปีที่แล้ว +34

    Hey Nick, thanks for the awesome videos. Are you planning or releasing a couple of videos about DDD?

  • @XXnickles
    @XXnickles 2 ปีที่แล้ว +27

    Something that I have never liked about the reflection based scanning is there is not clarity on how the dependencies are being loaded and there is a lot of implicit "magic" that needs to be explained before somebody who is not used to it works in a given code base. Also, this is on top of the DI container itself, which already has a lot of "sorcery" on it. That happened in a project I worked on, where we have to explain a person that just got onboard how the dependencies were being loaded and the conventions followed. What you get on "cleanness" you lose it in readability, and I believe (and studies have stated) the second is actually preferable.

    • @dire_prism
      @dire_prism 2 ปีที่แล้ว +4

      +1
      I very much dislike classes magically being hooked up just because they exist and use some attribute.

  • @joaoantunes8101
    @joaoantunes8101 2 ปีที่แล้ว

    Awesome! Today i was just trying to make my services registering more cleaner :) now i now the path!!!

  • @DiegoXLT
    @DiegoXLT 2 ปีที่แล้ว +1

    The cleanest approach (?) weather you use assembly scanning or call installers one by one is to have the installer file inside the assembly it is installing.
    This way only type that Startup.cs containing assembly needs to have access to is the installer itself (at least for registration purposes) - everything else can be internal and invisible to the Startup.cs assembly. The type can also be used as assembly marker.
    This approach also facilitates having less dependencies for intagration tests as you can just pick up the Installer/Module thingy and register one module if you like.

  • @muhammadasadhaider6893
    @muhammadasadhaider6893 2 ปีที่แล้ว +2

    Hey Nick, a suggestion, please link the videos that you talk about that are prerequisites to the concept you are talking about, thanks for the great content!

  • @sunnypatel1045
    @sunnypatel1045 2 ปีที่แล้ว

    Thank you for this mate!

  • @rajm1976
    @rajm1976 2 ปีที่แล้ว

    Nice. I remember doing this with Castle Windsor but couldnt figure it out for MS DI framework.

  • @bphatness3924
    @bphatness3924 2 ปีที่แล้ว

    Awesome stuff Nick. My startup.cs extensions were getting ugly!

  • @iGexogen
    @iGexogen 2 ปีที่แล้ว +1

    Nick, do you know is it possible to do some dynamic assembly discovery/loading to implement pluggable architecture in net core / 5+? In net framework was AppDomain and ability to scan folders for assemblies that are not referenced directly and not loaded with application to load them as plugins, is there any alternative in net core, maybe manipulations with deps.json?

  • @shashikantpawar7069
    @shashikantpawar7069 2 ปีที่แล้ว

    @Nick - Out of context question - Is any big company architecture use net core for its microservice architecture and any resources for that i need to check the complex problem

  • @aughey
    @aughey 2 ปีที่แล้ว

    Something to consider, if you have multiple Add*From*() methods that trickle down like in your example, consider one method that takes an IEnumerable and then create convenience methods that generate the IEnumerable for different reflection schemes. Similar code, but refactors and separates the assembly traversal code to one module that only does reflection and another that only does Dependency Injection. This also allows the user to write their own reflection traversal if needed.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      There is such a method in the video.

    • @aughey
      @aughey 2 ปีที่แล้ว

      Using this idea, a nice reusable fluent reflection module could be written that might look like ClassesInSameNamespaceAs(typeof(IAPIAssemblyMarker)).ThatImplementInterface(IMyInterface).ToEnumerable()

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      @@aughey I see what you mean now. yeah that's possible, but at that point you should be using Scrutor that already does all that for you.

  • @Hadda90
    @Hadda90 2 ปีที่แล้ว

    Hey Nick, I have a little off-topic question. What plugins do you use for Rider? What do you think is a must have?
    Greetings from Germany

  • @scorpions3834
    @scorpions3834 2 ปีที่แล้ว

    Hello, Guys, I am using repository patterns for building WebApps and API project for a couple of years and I need to create one API project for large enterprise so should consider clean architecture pattern or stick to the repository pattern as I am not much familiar with the clean architecture design
    Also, it would be really helpful if you can provide advantages of clean architecture over a repository pattern designed and if there are any other patterns that you think is better than both of them then you can share that to
    Thank you

  • @tjlopez3765
    @tjlopez3765 2 ปีที่แล้ว

    How does this work for services/assemblies that need to be created in a specific order? A common example would be services.AddAuthorization() and services.AddAuthentication()

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +2

      That's why the IInstaller has an Order property. You prioritize the different calls in the right order

  • @PlerbyMcFlerb
    @PlerbyMcFlerb 2 ปีที่แล้ว

    Note that you should also often filter out generic types in your assembly scanning

  • @dcl525
    @dcl525 2 ปีที่แล้ว +3

    Is it really that hard to write an extension on IServiceCollection to do the registration somewhere else? I think the benefit of clear, visible dependency registration for the sake of other developers understanding what's going on quickly and easily greatly outweighs reducing the code by a few lines. On the one hand, don't jam everything in the Startup file. On the other hand, if your service registrations are starting to look like spaghetti you may want to rethink the size of the service itself, unless you're into the monolithic life :)

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +2

      It's not. If you watched the full video, this is the exact advice I give at the end.

    • @dcl525
      @dcl525 2 ปีที่แล้ว +1

      @@nickchapsas Nick, it appears I've made a fool of myself.

  • @dorlg6655
    @dorlg6655 2 ปีที่แล้ว

    hey Nick, non-related question, what's your opinion about Kotlin?

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      Really good language

  • @twiksify
    @twiksify 2 ปีที่แล้ว +2

    Assembly scanning can be very convenient, however the drawback is the performance hit due to reflection. Source generation can help to solve that, however they are quite complex. So a middle ground could be to use assembly scanning in a unit test to verify all types are accounted for.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +3

      It’s only the application’s startup that will be a few microseconds slower. There is no real drawback and to be honest I’d rather have my startup be a few microseconds slower than my compilation a few seconds for the source generators

  • @MrJooni91
    @MrJooni91 2 ปีที่แล้ว +1

    I don't get it. Why not use simple extension methods for registering groups of services? Less code, less reflection, less project dependencys, but much cleaner and convenient. Like written about in the Microsoft docs for AspNet Core dependency injection.

    • @dcl525
      @dcl525 2 ปีที่แล้ว +1

      Totally agree - this is what I've always done and it's clean, clear and concise. You can see what exactly is being registered, how it's scoped, plainly and easily

  • @CabbageYe
    @CabbageYe 2 ปีที่แล้ว +2

    Is this basically Scrutor?

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +2

      Scrutor is a wrapper around assembly scanning

  • @JasonBock
    @JasonBock 2 ปีที่แล้ว

    Would be interesting to see if you could make this source generator-based.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      You could technically could there is absolutely no point except from some microseconds less during startup

    • @JasonBock
      @JasonBock 2 ปีที่แล้ว

      @@nickchapsas which is why I said "interesting". There are always trade-offs and measuring would show if the effort is worth it or not.

  • @user-yp6fz7ox7l
    @user-yp6fz7ox7l 2 ปีที่แล้ว

    .NET 6 have a new cleaner mechanism for startup.

  • @HiImKyle
    @HiImKyle 2 ปีที่แล้ว

    "All those packages, popular ones", I don't think I've heard a single one of them so that's a good start for me..

  • @DaviGn
    @DaviGn 2 ปีที่แล้ว +1

    Microsoft could have an assembly scanning for EF Mapping Fluent API classes, I always use a method that I built in every project.

  • @acuddlycactus
    @acuddlycactus 2 ปีที่แล้ว +1

    Tricks/tools like this may have the "cool" factor (and believe me, I love the cool factor), but I'll never reach for a tool if it relies heavily on reflection. In my opinion, it's just unnecessary overhead.

    • @Velociapcior
      @Velociapcior 2 ปีที่แล้ว +1

      but this code only executes at the start of application and these are only few methods it's not a lot of overhead

    • @acuddlycactus
      @acuddlycactus 2 ปีที่แล้ว

      @@Velociapcior I was speaking in a general sense. I've worked on many projects where libraries such as Spring DI increased the application startup time to over a minute (in a large application). Reflection can sometimes cripple an application and degrade the UX. Never underestimate how a single architectural decision can ruin the experience for your users. Just like conversations, first impressions count.

    • @Velociapcior
      @Velociapcior 2 ปีที่แล้ว

      @@acuddlycactus I do agree with you that using reflection in business process is a very bad idea. Nevertheless starting application is not a business process. And if application starts for over a minute, it's just to big

  • @jexrabbit
    @jexrabbit 2 ปีที่แล้ว +4

    Strongly disagree about the assembly marker interface type, because you're just cluttering your assembly with unneeded public types. Yes, you could of course make it internal, but still it seems forced. Just use any type of the assembly, as you did before. The whole problem could be prevented though, if C# had the possibility of specifying an assembly by name, just like the type...

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +4

      You shouldn't make it internal because you might wanna call the marker for a project that is a dependency to the main project.

    • @DayOfCasual
      @DayOfCasual 2 ปีที่แล้ว +5

      Marker interfaces are frowned upon in official microsoft docs too and are explicitly called an anti pattern.
      Link: docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1040

    • @iGexogen
      @iGexogen 2 ปีที่แล้ว +1

      For assembly scanning I prefer specifying some base type that is relevant to whole assembly's purpose. I use marker interfaces only if some classes really implement them, to be later inspected by reflection, it makes more sense than assembly level marker interface.

  • @shreyasjejurkar1233
    @shreyasjejurkar1233 2 ปีที่แล้ว +1

    60% of .NET works on reflection!

  • @the_udmurt
    @the_udmurt 2 ปีที่แล้ว +6

    Yet another abstraction for abstraction

  • @ardavaztterterian1211
    @ardavaztterterian1211 2 ปีที่แล้ว

    I'm always first!