dodyg / practical-aspnetcore

Practical samples of ASP.NET Core 8.0, 7.0, 6.0, 5.0, 3.1, 2.2, and 2.1,projects you can use. Readme contains explanations on all projects.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Dependency Injection example 3 - CurrentDomain.GetAssemblies()

dluc opened this issue · comments

Looking at https://github.com/dodyg/practical-aspnetcore/blob/net6.0/projects/dependency-injection/dependency-injection-3/Program.cs - as far as I know this code

var types = System.AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(x => x.GetTypes())
    .Where(p => type.IsAssignableFrom(p) && p.IsClass);

will find only types in assemblies loaded to this moment. For perf reason, .NET loads assemblies only when needed, so GetAssemblies() is often only a subset of all the app dependencies/assemblies.

A couple of options (not sure if there are more or if there's a way to force all assemblies to be discoverable):

  1. introducing static references to all assemblies, so they are loaded when the app starts
  2. scanning the folder and manually load each assembly before calculating types (caching the result if possible, so this is done only once or on demand)

Hi @dluc

Just landing to this issue, you meant something like referencing the .dll first by reflection and then retrieves a list of assemblies for instance? I would like to contribute to this if possible :)

@dalbarracin yes that should work. Referencing to any class inside each DLL with force .NET to load all assemblies, then GetAssemblies will return the full list. Something like this:

string[] NS_TO_IGNORE = { "System." };
string[] referencedPaths = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll");
foreach (var path in referencedPaths)
{
    var filename = path.Split(Path.DirectorySeparatorChar).LastOrDefault();
    if (filename != null && !NS_TO_IGNORE.Any(x => filename.StartsWith(x)))
        AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(path));
}

var types = System.AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(x => x.GetTypes())
    .Where(p => type.IsAssignableFrom(p) && p.IsClass);

Sounds doable @dluc 👍🏻

Also, just to avoid leaking types it would probably be a good idea to create a new AppDomain and Load/Unload the Assemblies if needed but I think that's out of scope.

I will work on this.