简体   繁体   中英

dotnet core get a list of loaded assemblies for dependency injection

I'm using AutoFac to automatically register dependencies based on their interface implementations like so:

builder.RegisterAssemblyTypes(Assembly.GetEntryAssembly()).AsImplementedInterfaces();

This works great for the entry assembly, but what about all of the related assemblies?

I'd like to do something like:

IList<Assembly> assemblies = GetLoadedAssemblies();
foreach(var assembly in assemblies)
{
  builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();
}

I've searched and see a bunch of .netcore 1.0 stuff with AssemblyLoadContext, etc., but that no longer seems to exist in 1.1. Basically, when you search, you get lots of outdated references to stuff that no longer works.

There's got to be a way to get the currently loaded assemblies.

How can I do this?

In .NET Core 2.0 Lots of APIs were brought from .NET Framework, among them is AppDomain.CurrentDomain.GetAssemblies() which allows you to get the assemblies that have been loaded into the execution context of application domain. Of course the concept wasn't fully ported from .NET Framework to .NET Core so you can't create your own app domains and treat them as unit of isolation inside single process (so you only have one app domain). But this is enough for what you want to achieve.

You can use Scrutor which is working with .netstandard 1.6 or take a look how they're doing it here.

    public IImplementationTypeSelector FromAssemblyDependencies(Assembly assembly)
    {
        Preconditions.NotNull(assembly, nameof(assembly));

        var assemblies = new List<Assembly> { assembly };

        try
        {
            var dependencyNames = assembly.GetReferencedAssemblies();

            foreach (var dependencyName in dependencyNames)
            {
                try
                {
                    // Try to load the referenced assembly...
                    assemblies.Add(Assembly.Load(dependencyName));
                }
                catch
                {
                    // Failed to load assembly. Skip it.
                }
            }

            return InternalFromAssemblies(assemblies);
        }
        catch
        {
            return InternalFromAssemblies(assemblies);
        }
   }

This is an old question, but none of the answers works for me.
I use autofac with asp.net core webapi project (.net 6).

This is where I need to get assemblies:

host
// autofac
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
// autofac container
.ConfigureContainer<ContainerBuilder>(builder => {
       // get assemblies for register
       var assemblies = ???
       builder.RegisterAssemblyTypes(assemblies).AsImplementedInterfaces()...
});

The project is desinged by DDD, dependcies are like this:

webapi -> domain,infra
infra -> domain

For my situation:
AppDomain.CurrentDomain.GetAssemblies() can only get webapi assembly.
BTW: Assembly.GetEntryAssembly() can get the webapi assebmly too. webapiAssembly.GetReferencedAssemblies() can only get domain project's assembly. Can't find the infra assembly.

Why GetReferencedAssemblies() doest not get all of the referenced assemblies as expected?

It's because in my project, webapi uses an repository interface, which is defines in domain, but implements in infra. Webapi project doesn't make any direct dependcy with infra layer (use class/interface defined in infra). So the infra assembly is not included.

If webapi has a directly dependcy with infra, use GetReferencedAssemblies() would be just fine.

Here is another solution that works for me:
Use DependencyContext which is inclued in Microsoft.Extensions.DependencyModel (nuget package) to get all assemblies that I wanted (webapi, domain, infra).

public static class AssemblyHelper
{
    // get all assemblies that I wanted
    // you may want to filter assemblies with a namespace start name
    public static Assembly[] GetAllAssemblies(string namespaceStartName = "")
    {
        var ctx = DependencyContext.Default;
        var names = ctx.RuntimeLibraries.SelectMany(rl =>  rl.GetDefaultAssemblyNames(ctx));

        if (!string.IsNullOrWhiteSpace(namespaceStartName))
        {
            if (namespaceStartName.Substring(namespaceStartName.Length - 1, 1) != ".")
                namespaceStartName += ".";

            names = names.Where(x => x.FullName != null && x.FullName.StartsWith(namespaceStartName)).ToArray();
        }

        var assemblies = new List<Assembly>();
        foreach (var name in names)
        {
            try
            {
                assemblies.Add(Assembly.Load(name));
            }
            catch { } // skip
        }

        return assemblies.ToArray();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM