practical-aspnetcore icon indicating copy to clipboard operation
practical-aspnetcore copied to clipboard

Dependency Injection example 3 - CurrentDomain.GetAssemblies()

Open dluc opened this issue 2 years ago • 3 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)

dluc avatar May 23 '22 04:05 dluc

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 avatar Oct 02 '22 15:10 dalbarracin

@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);

dluc avatar Oct 03 '22 00:10 dluc

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.

dalbarracin avatar Oct 03 '22 01:10 dalbarracin