How Assembly Scanning keeps your .NET code clean

Поделиться
HTML-код
  • Опубликовано: 6 ноя 2024

Комментарии • 48

  • @XXnickles
    @XXnickles 3 года назад +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 3 года назад +4

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

  • @trawsonn
    @trawsonn 3 года назад +34

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

  • @DiegoXLT
    @DiegoXLT 3 года назад +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.

  • @joaoantunes8101
    @joaoantunes8101 3 года назад

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

  • @aughey
    @aughey 3 года назад

    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  3 года назад

      There is such a method in the video.

    • @aughey
      @aughey 3 года назад

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

    • @nickchapsas
      @nickchapsas  3 года назад

      @@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.

  • @muhammadasadhaider6893
    @muhammadasadhaider6893 3 года назад +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!

  • @rajm1976
    @rajm1976 3 года назад

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

  • @twiksify
    @twiksify 3 года назад +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  3 года назад +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

  • @PlerbyMcFlerb
    @PlerbyMcFlerb 3 года назад

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

  • @bphatness3924
    @bphatness3924 3 года назад

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

  • @dcl525
    @dcl525 3 года назад +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  3 года назад +2

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

    • @dcl525
      @dcl525 3 года назад +1

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

  • @Hadda90
    @Hadda90 3 года назад

    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

  • @iGexogen
    @iGexogen 3 года назад +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?

  • @HiImKyle
    @HiImKyle 3 года назад

    "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..

  • @sunnypatel1045
    @sunnypatel1045 3 года назад

    Thank you for this mate!

  • @shashikantpawar7069
    @shashikantpawar7069 3 года назад

    @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

  • @user-yp6fz7ox7l
    @user-yp6fz7ox7l 3 года назад

    .NET 6 have a new cleaner mechanism for startup.

  • @tjlopez3765
    @tjlopez3765 3 года назад

    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  3 года назад +2

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

  • @scorpions3834
    @scorpions3834 3 года назад

    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

  • @JasonBock
    @JasonBock 3 года назад

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

    • @nickchapsas
      @nickchapsas  3 года назад

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

    • @JasonBock
      @JasonBock 3 года назад

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

  • @MrJooni91
    @MrJooni91 3 года назад +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 3 года назад +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

  • @dorlugasigal
    @dorlugasigal 3 года назад

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

  • @DaviGn
    @DaviGn 3 года назад +1

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

  • @CabbageYe
    @CabbageYe 3 года назад +2

    Is this basically Scrutor?

    • @nickchapsas
      @nickchapsas  3 года назад +2

      Scrutor is a wrapper around assembly scanning

  • @the_udmurt
    @the_udmurt 3 года назад +6

    Yet another abstraction for abstraction

  • @shreyasjejurkar1233
    @shreyasjejurkar1233 3 года назад +1

    60% of .NET works on reflection!

  • @acuddlycactus
    @acuddlycactus 3 года назад +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 3 года назад +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 3 года назад

      @@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 3 года назад

      @@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 3 года назад +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  3 года назад +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 3 года назад +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 3 года назад +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.

  • @ardavaztterterian1211
    @ardavaztterterian1211 3 года назад

    I'm always first!